Järjestelmäviesti:Gadget-Otsikot.js

Wikisanakirjasta

Huomautus: Selaimen välimuisti pitää tyhjentää asetusten tallentamisen jälkeen, jotta muutokset tulisivat voimaan.

  • Firefox ja Safari: Napsauta Shift-näppäin pohjassa Päivitä, tai paina Ctrl-F5 tai Ctrl-R (⌘-R Macilla)
  • Google Chrome: Paina Ctrl-Shift-R (⌘-Shift-R Macilla)
  • Internet Explorer ja Edge: Napsauta Ctrl-näppäin pohjassa Päivitä tai paina Ctrl-F5
  • Opera: Paina Ctrl-F5.
(function () {

    /**
     * Valikossa näkyvät kieliotsikot. Ei vaikuta otsikoiden järjestykseen. Se määräytyy 
     * `kielijarj`-funktiolla.
     */
    var kielet = [ "Kansainvälinen", "Suomi", "Englanti", "Espanja", "Ranska", "Ruotsi", "Saksa", 
                   "Venäjä", "Viro", "Lähteet", "Viitteet" ];
 
    /**
     * Sanaluokat yms.. Valikossa näkyvät. Osioiden järjestys määräytyy aakkosjärjestyksen mukaan.
     */
    var taso3 = [ "Aakkonen", "Adjektiivi", "Adverbi", "Erisnimi", "Fraasi", "Interjektio", 
                  "Konjunktio", "Lyhenne", "Numeraali", "Postpositio", "Prefiksi", "Prepositio", 
                  "Pronomini", "Substantiivi", "Suffiksi", "Supistuma", "Verbi" ];
 
    /**
     * Sanaluokkien aliosiot. Otsikoiden järjestys ja valikossa näkyvät.
     */
    var taso4 = [ "Ääntäminen", "Taivutus", "Huomautukset", "Etymologia", "Käännökset", 
                  "Lainaukset", "Liittyvät sanat", "Idiomit", "Aiheesta muualla", "Lähteet" ];
 
    /**
     * Liittvät sanat. Otsikoiden järjestys ja valikossa näkyvät.
     */
    var liittyvat = [ "Rinnakkaiset kirjoitusasut", "Rinnakkaismuodot", "Synonyymit", 
                      "Vastakohdat", "Johdokset", "Yhdyssanat", "Yhdyssanat ja sanaliitot", 
                      "Tästä johtuvat tytärkielten sanat", "Lainat muissa kielissä", 
                      "Yläkäsitteet", "Vieruskäsitteet", "Alakäsitteet", "Osakäsitteet", 
                      "Kokonaiskäsitteet" ];
 
    /**
     * Osioihin lisättävä oletusteksti.
     */
    var oletusarvot = { 
        "." : [ null ],
        "Suomi" : 
        {
            "." : [ null ],
            "Adjektiivi" : { "." : ["{{" + "fi-adj||" + "}}"] },
            "Adverbi" : { "." : ["{{" + "fi-adv||" + "}}"] },
            "Substantiivi" : 
            {
                "." : ["{{" + "fi-subs||" + "}}" ],
                "Taivutus" : { "." : ["{{" + "fi-subs-|" + "}}"] },
            },
            "Verbi" : { "." : ["{{" + "fi-verbi||" + "}}"] },
            "*" : 
            {
                "Ääntäminen" : { "." : ["{{" + "fi-äänt" + "}}"] },
            },
        },
        "Englanti" : 
        {
            "Adjektiivi" : { "." : ["{{" + "en-adj||" + "}}"] },
            "Adverbi" : { "." : ["{{" + "en-adv||" + "}}"] },
            "Substantiivi" : { "." : ["{{" + "en-subs||" + "}}" ] },
            "Verbi" : { "." : ["{{" + "en-verbi||" + "}}" ] },
        },
        "Espanja" : 
        {
            "Adjektiivi" : { "." : ["{{" + "es-adj||" + "}}"] },
            "Adverbi" : { "." : ["{{" + "es-adv|" + "}}"] },
            "Substantiivi" : { "." : ["{{" + "es-subs||" + "}}" ] },
            "Verbi" : { "." : ["{{" + "es-verbi||" + "}}"] },
        },
        "Ruotsi" : 
        {
            "Adjektiivi" : { "." : ["{{" + "sv-adj||" + "}}"] },
            "Adverbi" : { "." : ["{{" + "sv-adv|" + "}}"] },
            "Substantiivi" : { "." : ["{{" + "sv-subs||" + "}}"] },
            "Verbi" : 
            { 
                "." : ["{{" + "verbi|sv|" + "}}"], 
                "Taivutus" : { "." : ["{{" + "sv-verbi-|" + "}}"] },
            },
        },
        "Saksa" : 
        {
            "Adjektiivi" : { "." : ["{{" + "de-adj||" + "}}"] },
            "Adverbi" : { "." : ["{{" + "de-adv|" + "}}"] },
            "Substantiivi" : { "." : ["{{" + "de-subs||" + "}}"] },
            "Verbi" : { "." : ["{{" + "de-verbi||" + "}}"] },
        },
        "Venäjä" : 
        {
            "Adjektiivi" : { "." : ["{{" + "ru-adj||" + "}}"] },
            "Adverbi" : { "." : ["{{" + "adverbi|ru|" + "}}"] },
            "Substantiivi" : { "." : ["{{" + "ru-subs||" + "}}"] },
            "Verbi" : { "." : ["{{" + "ru-verbi||" + "}}"] },
        },
        "Viitteet" : 
        {
            "." : ["{{viitteet}}"],
        },
        "Lähteet" :
        {
            "." : "",
        },
        "*" : 
        {
            "." : [-1], // erikoisarvo, joka estää rivinvaihdon lisäämisen
            "Adjektiivi" : { "." : ["{{" + "adjektiivi|" + "}}"] },
            "Adverbi" : { "." : ["{{" + "adverbi|" + "}}"] },
            "Erisnimi" : { "." : ["{{" + "erisnimi|" + "}}"] },
            "Fraasi" : { "." : ["{{" + "fraasi|" + "}}"] },
            "Interjektio" : { "." : ["{{" + "interjektio|" + "}}"] },
            "Konjunktio" : { "." : ["{{" + "konjunktio|" + "}}"] },
            "Lyhenne" : { "." : ["{{" + "lyhenne|" + "}}"] },
            "Numeraali" : { "." : ["{{" + "numeraali|" + "}}"] },
            "Partikkeli" : { "." : ["{{" + "partikkeli|" + "}}"] },
            "Postpositio" : { "." : ["{{" + "postpositio|" + "}}"] },
            "Prefiksi" : { "." : ["{{" + "prefiksi|" + "}}"] },
            "Prepositio" : { "." : ["{{" + "prepositio|" + "}}"] },
            "Pronomini" : { "." : ["{{" + "pronomini|" + "}}"] },
            "Substantiivi" : 
            {
                "." : ["{{" + "substantiivi|" + "}}"],
            },
            "Suffiksi" : { "." : ["{{" + "suffiksi|" + "}}"] },
            "Supistuma" : { "." : ["{{" + "supistuma|" + "}}"] },
            "Verbi" : { "." : ["{{" + "verbi|" + "}}"] },
            "*" : 
            {
                "." : [ null, "{{" + "yhteys||k=" + "}}" ], 
                "Ääntäminen" : { "." : ["{{" + "IPA|" + "}}"] },
                "Käännökset" : { "." : ["{{" + "su" + "bst:kohta|||\n\n|loppu" + "}}"] },
                "Etymologia" : { "." : ["{{" + "ety|" + "}}"] },
                "Lainaukset" : { "." : ["{{" + "lainaus||}}\n\n{{lainaus-päättyy" + "}}"] },
                "Liittyvät sanat" : 
                { 
                    "." : [-1],
                    "Johdokset" :  { "." : ["{{" + "johdokset|||" + "}}"] },
                    "Yhdyssanat" :  { "." : ["{{" + "yhdyssanat|||" + "}}"] },
                    "Yhdyssanat ja sanaliitot" :  { "." : ["{{" + "yhdyssanat|||" + "}}"] },
                },
            },
        },
    };


    // Sivun otsikot.
    var osat = [];

    /**
     * Osion polku osat-taulukon indekseinä.
     */
    var polku = [];

    /**
     * Tekstin pituus ilman kielilinkkejä ja luokkia.
     */
    var tekstin_loppu = -1;

    /**
     * Kielilinkit ja luokat sivun lopusta.
     */
    var luokat = "";
    
    var $textbox = $('#wpTextbox1');

    /**
     * Sektion numero, jos editoidaan artikkelin osaa.
     */
    var wpSection = $('input[name$="wpSection"]').val();


    /**
     * Tekee indeksipolusta tekstipolun. Esim. [,,3,4] -> [Suomi,Adjektiivi]
     */
    function tekstipoluksi(polk) {
        var opolku = [];
        for ( var i = 2; i < polk.length; i++ )
            if ( typeof polk[i] !== "undefined" ) {
                if ( polk[i] === null )
                    opolku.push(null);
//              else if ( polk[i] == -1 )
//                  opolku.push("[sivu]");
                else
                    opolku.push(osat[polk[i]][2]);
            }
        return opolku;
    }

    /**
     * Palauttaa oletusarvon taulukosta 'oletusarvot' osiolle, jonka polku on 'polku'.
     */
    function oletusarvo(polku) {
        function _apu(opolku, i, okohta) {
            if ( i == opolku.length ) {
                if ( "." in okohta )
                    return okohta["."][0];
                return null;
            }

            var ret = null;
            if ( opolku[i] in okohta )
                ret =  _apu(opolku, i+1, okohta[opolku[i]]);
            if ( !ret && "*" in okohta )
                ret = _apu(opolku, i+1, okohta["*"]);
            return ret;
        }

        var ret =  _apu(polku, 0, oletusarvot) ;
        if ( ret === null ) ret = "";
        return ret;
    }


    function kielijarj(k) {
        switch ( k ) {
        case "Kansainvälinen":
            return -2;
        case "Suomi":
            return -1;
        case "Lähteet":
            return +1;
        case "Viitteet":
            return +2;
        default:
            return 0;
        }
    }

    /*
     * Jakaa tekstin 'teksti' kahteen osaan joista jälkimmäinen sisältää kielilinkit ja luokat
     * ja ensimmäinen muun tekstin. Palauttaa taulukon.
     */
    function erota_luokat(teksti) {
        var p = teksti.search(/\n(\[\[[\w-]+:[^\]]+\]\]\s*\n*)+$/);
        if ( p == -1 ) {
            p = teksti.length;
        }
        return [ teksti.substring(0, p), teksti.substring(p) ];
    }

    /**
     * Palauttaa otsikkovalikon otsikot polulle 'polku'.
     * Param polku: [], jonka alkiot ovat indeksejä osat-taulukkoon.
     */
    function hae_otsikot(polku) {
		var grp;
		var i;
        var sivu = false;
        var taso2ots = null;
        var taso3ots = null;
        var taso4ots = null;
        var otsikot = [];

        if ( polku[1] !== null ) sivu     = true;
        if ( polku[2] !== null && osat[polku[2]] ) taso2ots = osat[polku[2]][2];
        if ( polku[3] !== null && osat[polku[3]] ) taso3ots = osat[polku[3]][2];
        if ( polku[4] !== null && osat[polku[4]] ) taso4ots = osat[polku[4]][2];

        otsikot.push("<option>- Lisää otsikko -</option>");

        if ( taso4ots == "Liittyvät sanat" ) {
            grp = $("<optgroup label='Liittyvät sanat'></optgroup>");
            grp.prop("level", 5);

            for ( i in liittyvat ) { 
                grp.append("<option>" + liittyvat[i] + "</option>");
            }

            otsikot.push(grp);
        }

        if ( taso3ots ) {
            if ( taso3.indexOf(taso3ots) != -1 
                 && taso2ots != "Lähteet" 
                 && taso2ots != "Viitteet" ) {
                
                grp = $("<optgroup label='" + taso3ots + "'></optgroup>");
                grp.prop("level", 4);

                for ( i in taso4 ) { 
                    // Suodatetaan Käännökset-otsikko pois, jos kieli ei ole suomi tai 
                    // määrittelemätön kieli.
                    if ( taso4[i] != "Käännökset" || (taso2ots == "Suomi" || taso2ots === null) ) {
                        grp.append("<option>" + taso4[i] + "</option>");
                    }
                }

                otsikot.push(grp);
            }
        }

        if ( taso2ots ) {
            grp = $("<optgroup label='" + taso2ots + "'></optgroup>");
            grp.prop("level", 3);

            for ( i in taso3 ) { 
                grp.append("<option>" + taso3[i] + "</option>");
            }

            otsikot.push(grp);
        }


        if ( sivu ) {
            grp = $("<optgroup label='- sivu -'></optgroup>");
            grp.prop("level", 2);

            for ( var j in kielet ) { 
                grp.append("<option>" + kielet[j] + "</option>");
            }

            otsikot.push(grp);
        }

        return otsikot;
    }


    /**
     * Palauttaa true, jos otsikko 'a' tulee ennen otsikkoa 'b', kun molempien taso on 'taso'.
     */
    function tulee_ennen(taso, a, b) {
        switch ( taso ) {
        case 2:  // kielet
            var ai = kielijarj(a), bi = kielijarj(b);
            if ( ai == bi )
                return (a < b); 
            return (ai < bi);
        case 3:  // Sanaluokat
            return (a < b);
        case 4:  // Sanaluokan aliosiot
            return (taso4.indexOf(a) < taso4.indexOf(b));
        case 5:  // liittyvät sanat
            return (liittyvat.indexOf(a) < liittyvat.indexOf(b));
        }
        return false;
    }

    function lisaa_teksti(teksti, valitse) {
        var ppos = $textbox.textSelection('getCaretPosition', { 'startAndEnd' : true });
        var spos = ppos[0];
        var epos = ppos[1];

        if ( false && document.queryCommandSupported('insertText')) {
            $textbox.focus();
            document.execCommand('insertText', false, teksti);
        } else {
            $textbox.val($textbox.val().substring(0, spos) + teksti 
                         + $textbox.val().substring(epos, $textbox.val().length));
        }
        epos = spos + teksti.length;
        $textbox.textSelection('setSelection', { 'start': spos, 'end': epos }); 
        $textbox.focus();
    }

    function lisaa_blokki(pos, otsikko, osio) {
        if ( pos != -1 ) $textbox.textSelection('setSelection', { 'start': pos, 'end': pos }); 
        
        var ppos = $textbox.textSelection('getCaretPosition', { 'startAndEnd' : true });
        var spos = ppos[0]-1, epos = ppos[1]-1;

        // Valitaan tyhjä alue osioiden välistä.
        while ( $textbox.val()[spos] == "\n" ) spos--; spos += 1;
        while ( $textbox.val()[epos] == "\n" ) epos++;
        $textbox.textSelection('setSelection', { 'start': spos, 'end': epos }); 

        //HÄ?????????
        // Lisätään ennen ensimmäistä otsikkoa vain yksi rivinvaihto.
        if ( spos == 0 ) alku = "\n"; else alku = "\n\n";

        // Haetaan lisäyksessä liikkunut kursori.
        var spos = $textbox.textSelection('getCaretPosition', { 'startAndEnd' : false });
        spos += alku.length + otsikko.length + 1;

        var epos = spos + osio.length;
        if ( osio != "" ) epos -= 1; // Miksi tarvitaan??
        var teksti = alku + otsikko + "\n" + osio + "\n";
        lisaa_teksti(teksti, false);

        // Valitaan lisätty osio, pois lukien viimeinen rivinvaihto.
        $textbox.textSelection('setSelection', { 'start': spos, 'end': epos }); 
        
    }

    function tee_otsikko(taso, teksti) {
        var eq = Array(taso+1).join("=");
        return eq + teksti + eq;
    }
    
    function kirjoita_teksti() {
        var rivit = [];
        for ( var i in osat ) {
            var lvl = osat[i][1];
            if ( lvl > 0 ) {
                rivit.push(tee_otsikko(osat[i][2]));
            } else {
                rivit.push(osat[i][2]);
            }
        }
        // Yhdistetään osat.
        var txt = rivit.join("\n") + luokat;
        $textbox.val(txt);
    }
    

    function lisaa_otsikko(taso, lisattava) {
        var i = 0, a = 0, l = -1;
        if ( taso == 2 ) a = 0;
        else a = polku[taso-1]+1;

        // Etsitään otsikko, jota ennen tämä otsikko lisätään.
        for ( var i = a; i < osat.length; i++ ) {
            if ( osat[i][1] < taso ) {
                break;
            } else if ( osat[i][1] == taso ) {
                if ( tulee_ennen(taso, lisattava, osat[i][2]) ) {
                    break;
                }
            }
        }

        // Lasketaan uusi kursorin kohta.
        var pos = 0;
        if ( i < osat.length ) {
            pos = osat[i][0];
        } else {
            pos = tekstin_loppu;
        }

        // Uuden osion polku
        var tpolku = tekstipoluksi(polku.slice(0, taso))
        tpolku.push(lisattava);
        var blokki = oletusarvo(tpolku);
        // Jos arvo on -1 jätetään rivinvaihto lisäämättä
        if ( blokki == -1 ) blokki = ""; else blokki += "\n";
        lisaa_blokki(pos, tee_otsikko(taso, lisattava), blokki);
    }

    function ovalikko_onchange() {
        var $otsikkovalikko = $("#otsikkovalikko");
        var $valittu = $otsikkovalikko.find("option:selected");
        var lisattava = $valittu.text();

        if ( $otsikkovalikko.prop("selectedIndex") != 0 ) {
            var taso = $valittu.parent().prop("level");
            
            lisaa_otsikko(taso, lisattava);
            
            $textbox.focus();

        } else {
            //$textbox.focus();
        }

        $otsikkovalikko.children(':first').prop('selected', true);
    }



    function parsi_teksti() {
        var pos = $textbox.textSelection('getCaretPosition', { 'startAndEnd' : false }) + 1;
        var txt = "\n" + $textbox.val(); 
        var pat = /\n(==+)(.*)\1/g;
        var result;


        var arr = erota_luokat(txt);
        txt = arr[0];
        luokat = arr[1];
        tekstin_loppu = arr[0].length;

        // Taso, jolla kursori on.
        var postaso = 0;
        polku = [null, null, null, null, null];
        if ( wpSection == "" )  { polku[1] = -1; postaso = 1 };
        osat = [];

        while ( (result = pat.exec(txt)) !== null ) {
            // Matchin alku + 1. Huom. osoittaa otsikon alkuun eikä otsikkoa edelliseen
            // rivinvaihtoon, koska tekstin alkuun lisättiin ylimääräinen \n.
            var s = pat.lastIndex - result[0].length
            var taso = result[1].length;

            osat.push([ s, taso, result[2] ]);

            // Lopetetaan polun kokoaminen, jos ollaan yli kursorin kohdan.
            if ( s < pos ) {
                polku[taso] = osat.length-1;
                postaso = taso;
            }
        }

        polku = polku.slice(0, postaso+1);
    }

    function tayta_otsikkovalikko() {
        parsi_teksti();

        var lst = hae_otsikot(polku);
        $("#otsikkovalikko").empty();
        for ( var i in lst ) {
            $("#otsikkovalikko").append(lst[i]);
        }
    }





    function run($) {
        var $sailio = $('<span></span>');
        if ( $("#tyokalupakki").length == 0 ) {
            $textbox.before('<div id="tyokalupakki"></div>');
        }
        $("#tyokalupakki").append([ '<span class="tyokaluerotin" style="color: gray; ">'
                                    + ' | </span>', $sailio ]);

        var $ohje_lnk = $('<a href="/wiki/Ohje:Gadget-Otsikot">?</a></div>');
        var $ohje_span = $('<span class="ohjenappi"></span>');
        $ohje_span.html([ "[", $ohje_lnk, "]" ]);

        var $ovalikko = $('<select style="width: 15em;" id="otsikkovalikko" '
                          + 'title="Lisää otsikko [Ctrl-Alt-o]">'
                          + '<option>- Lisää otsikko -</option>'
                          + '</select>');

        $ovalikko.on("focus", tayta_otsikkovalikko);
        $ovalikko.on("change", ovalikko_onchange);
        $ovalikko.keyup(function(event) { 
            if ( event.keyCode == 27 ) /* ESC */ $textbox.focus();
            else if ( event.keyCode == 18 ) /* Enter */ event.preventDefault(); 
        });

        $sailio.append([ $ovalikko, " ", $ohje_span ]);

        $(document).keyup(function(event){
            if ( event.ctrlKey && event.altKey && event.keyCode == 79 ) { // 'o'
                $ovalikko.focus();
            }
        });
        $textbox.focus();
    }

    if ( (mw.config.get('wgAction') == "edit" || mw.config.get('wgAction') == "submit") 
         && mw.config.get('wgNamespaceNumber') == 0) {
        jQuery(document).ready(run);
    }

})();