Kehittäjäopas

Nörttivaroitus

Tämän opasosion sisältö on suunnattu ihmisille, joilla on liikaa aikaa ja kiinnostusta nörtteilyyn, sillä se kertoo teknisestä näkökulmasta L'Mathin laajentamisesta ja lisäosien koodaamisesta.

Keskeneräisyysvaroitus

Älä odota liikoja. L'Mathin lisäosarajapinta on alkeellinen, ja monimutkaisempien toiminnallisuuksien pakertamisessa voi tulla harmaita hiuksia. Lisäosatuki paranee luultavasti huomattavasti, jahka ohjelman etupuolen rewrite on valmis.

Tervetuloa kehittäjäoppaaseen. Täältä löydät tietoa L'Mathin lisäosatuesta, joka on toistaiseksi hieman vaiheessa.

Pyrkimys on pitkällä tähtäimellä se, että innokkaimmat käyttäjät voisivat kirjoittaa ohjelmistoon hyödyllisiä lisäosia, esimerkiksi erilaisten aineistojen ja materiaalien hyötykäyttöön, widgettien lisäämiseksi, kustomoimiseksi, ja niin edelleen.

Etenkin L'Mathin näkyvä osa (frontend) on tällä hetkellä melkoisessa spagettikunnossa; se pitäisi modernisoida ja kirjoittaa monilta osin kokonaan uusiksi. Lisäosa-API tulee kuitenkin olemaan jatkossakin samanlainen, joten sen käytön osalta ei kannata olla huolissaan. Jos taasen haluat tökkiä esimerkiksi UI-elementtejä suoraan jQueryllä, saattaa versioiden välillä tulla ongelmia, etenkin jos ja kun frontendin teknologioihin tulee myöhemmin muutoksia.

 

 

 

 

 

Johdanto

Hei, ja tervetuloa L'Mathin "kauniiseen" (kamalaan) lisäosakehitysdokumentaatioon. Lisäosarajapinnan tarkoitus on antaa käyttäjille (=nörteille) mahdollisuus parannella ohjelmistoa omilla lisäosilla ja -virityksillä.


Perusteet

L'Math perustuu Node.js- ja Electron-tekniikkaan, ja on siten kirjoitettu kokonaisuudessaan JavaScriptiä käyttäen. Uusille tuttavuuksille on mainittava, että ei, Java ja JavaScript eivät ole sama ohjelmointikieli, ja kyllä, JavaScriptiin voi nykyaikana törmätä myös muualla kuin selaimessa.

L'Math lataa lisäosat eli pluginit käyttäjäkohtaisesta datakansiosta:

  • Windowsilla: %APPDATA%\LMath\plugins
  • macOS:llä: ~/Library/Application Support/LMath/plugins
  • GNU/Linuxilla: ~/.local/share/LMath/plugins

Lisäosatuki lisättiin versiossa r1.7, joten sitä aiemmilla versioilla kyseistä plugins-kansiota ei edes löydy. Lisäosatuessa ei ole käytännössä eroja yksityis- ja oppilaitosversioiden välillä.

Lisäosien rakenne noudattaa seuraavaa kaavaa:

└ plugins/
   ├ plugin-id/
   │ ├ plugin.json           // the metadata file
   │ └ ...                   // other files
   └ example-plugin-id/
     ├ plugin.json
     └ modules/
       ├ front.js
       └ back.js

Jokainen lisäosa elää siis omassa alakansiossaan, jonka nimen täytyy olla pluginin id (täsmälleen sama kuin plugin.json-tiedostossa on määritelty).


Backend ja frontend

L'Math koostuu näkyvästä HTML5-frontendistä ja näkymättömästä Node.js-backendistä. Vaikka L'Math ei tällä hetkellä käytä hiekkalaatikoitua tilaa, ja Node.js-integraatio on sallittu myös frontendissä, on vahvasti suositeltavaa käyttää lisäosarajapinnan tarjoamia viestintäkeinoja, sillä Node.js-integraatio luultavasti poistuu käytöstä tulevissa päivityksissä.

Erityisesti frontendin puolella kannattaa noudattaa siis äärimmäistä varovaisuutta kaikkien maailmalta ja käyttäjiltä tulleiden syötteiden ja tiedostojen ym. kanssa.


Kehittäjätyökalut

L'Math on normaali Electron-pohjainen työpöytäkikkare. Saat kehittäjätyökalut ja konsolin auki frontendiin kolmella eri tavalla:

  • Avaamalla asetukset Ctrl/Cmd+K ja klikkaamalla teknisten asetusten välilehteä valikosta nopeasti noin kymmenen kertaa (tai kunnes devtoolit pomppaavat esiin)
  • Luomalla uuden sivun valikosta Ctrl/Cmd+T ja antamalla sen nimeksi tarkalleen Seesam aukene, konsoli! (tämä toimii hyvin varhaisista versioista alkaen)
  • Asettamalla ohjelman kehittäjätilaan flagilla --dev
    • Huom! Tämä vaihtaa ohjelman käyttämään kehitysrajapintaa ja kehityspatcheja. Käytä tätä flagia omalla vastuullasi; se saattaa rikkoa koko ohjelman väärällä versiolla.

Metatiedosto plugin.json

Lisäosan kansiossa tulee olla tiedosto plugin.json, joka sisältää metatietoja kyseisestä lisäosasta. Tiedosto muistuttaa hieman tyypillistä package.json-tiedstoa, mutta niitä ei pidä sekoittaa keskenään, koska L'Math käsittelee plugin-metatiedostoa omalla tyylillään.

Esimerkki plugin.json-tiedostosta:

{
    "id": "test-plugin",
    "name": "Test plugin 123",
    "description": "Just a test plugin",
    "author": "Maiva Mallikas",
    "modules": [
        {
            "type": "backend",
            "file": "modules/back.js"
        },
        {
            "type": "frontend",
            "file": "modules/front.js"
        }
    ],
    "pluginVersion": "1.0",
    "requiredVersion": "r1.7"
}

Metadatan id-kentän tulee olla sama kuin lisäosan kansion nimi. Jos metatiedostoa ei ole tai se on kelpaamaton, L'Math jättää lisäosan lataamatta.

Metadatassa on json-lista modules, jonka mukaan L'Math lataa backend- ja frontend-moduuleja. Jos type on arvoltaan backend, js-tiedosto ladataan ja kutsutaan taustaohjelmassa, ja vastaavasti arvolla frontend pääikkunassa.

JS-moduuleista tarkemmin seuraavassa osiossa.

JavaScript-moduulit

Kuten metatiedoston dokumentaatiossa todetaan, L'Math lataa kunkin lisäosan määrittämät JS-tiedostot taustaohjelmassa ja näkyvässä asiakasohjelmassa. Nämä JS-moduulit ladataan ohjelmistoon normaaleilla require-kutsuilla, ja niiden tulee palauttaa objekti, jossa on metodi init.

Moduuleille annetaan init-kutsun argumentteina tietyt rajapinnat ja objektit, joilla lisäosa voi vuorovaikuttaa ohjelmiston kanssa.


Backend-moduulit

Backendin puolella moduulin init-metodia kutsutaan kahdella parametrilla: logger ja LMathPluginAPI (backend-api), joista ensimmäinen on tavallinen log4js-lokikirjaston loggeri, ja jälkimmäinen on L'Mathin rajapintaobjekti.

Alla simppeli esimerkki backend-moduulista.

/*
 * Backend module
 */

module.exports = {
    init: (...args) => {

        const [ logger, api ] = args;
        
        logger.info('Hewwo! It is me, the new plugin!');

        api.messages.on('testMessage', (d) => {
            logger.info('Someone sent me a message! ' + d);
        });

    }
};

Frontend-moduulit

Myös frontend-moduulit saavat kaksi init-argumenttia: window (itse window-objekti) ja LMathPluginAPI (frontend-api). Ikkunan handlesta saa tarvittaessa käyttöön myös jQueryn (window.$) ja muuta hyödyllistä.

Tärkeää! L'Math ei anna virallista tukea lisäosille minkään muun kuin LMathPluginAPI-handlen kautta. Jos aiot "reverse-engineerata" L'Mathin frontendin ihmeellisyyksiä, huomioi, että versioiden välillä saattaa olla eroja, ja obfuskoitu frontendin JavaScript elää omaa elämäänsä julkaisujen välillä (objektinimet ja muuttujat eivät ole välttämättä samoja edes samalla versionumerolla).

Alla esimerkki frontend-moduulista, joka huutaa aiemman esimerkin backend-moduulille terveisiä.

/*
 * Frontend module
 */

module.exports = {
    init: (...args) => {

        const [ window, api ] = args;
        const { $, jQuery } = window;
        
        console.log('Hieee, greetings from the frontend!');
        setInterval(() => api.messages.send('testMessage', Date.now()), 2000);

    }
};

API-dokumentaatio

Purkkainen API-dokumentaatio löytyy erikseen Gitlabista. Onnea matkaan.

Event-systeemi

API toimii monilta osin tapahtumapohjaisesti ("event driven"). Voit kuunnella moduuleissasi erilaisia tapahtumahuutoja, ja joissain tapauksissa myös muuttaa niiden lopputulemia tai datasisältöjä.

Dokumentaatio Gitlabissa:

Esimerkki: Sivun sisällön muuttaminen ennen latausta

/*
* Backend module
*/

module.exports = {
    init: (...args) => {

        const [ logger, api ] = args;
        
        // Tämä muuttaa kaikkien avattavien sivujen sisällön
        // Comic Sans MS:llä kirjoitetuksi tekstiksi.
        api.events.on('pageImport', e => {
            e.content = `<div style="font-family: 'Comic Sans MS', cursive;">
                Haha! Just a prank...
            </div>`;
        });

    }
};

Esimerkki: Kaavan muuttaminen ennen renderöintiä

/*
* Frontend module
*/

module.exports = {
    init: (...args) => {

        const [ window, api ] = args;
        const { $, jQuery } = window;
        
        // Tämä muuttaa kaikista kaavoista plussat miinuksiksi...
        api.events.on('formulaRender', e => {
            e.latex = e.latex.replace(/\+/gmi, '-');
        })

    }
};

Julkaisu ja ekosysteemi

Toistaiseksi lisäosille ei ole keskitettyä julkaisupaikkaa. Sellainen kuitenkin saattaa ennemmin tai myöhemmin ilmestyä, jos ja kun ohjelmiston kokonaisarkkitehtuuri kokee parannuksia. Kätevää olisi siis esimerkiksi se, että ohjelmistossa olisi jokin tarkistettujen ja hyväksyttyjen lisäosien esittely- ja lataustoiminto, tai että lisäosia voisi asentaa vaikkapa raahaamalla niiden zip-paketit ohjelmaan.

Näin ollen lisäosien jakelu on tällä hetkellä hieman villin lännen tasolla: joudut tekemään paljon ylimääräistä työtä sen eteen, että käyttäjät saisivat lisäosia käyttöön helposti. Pahoittelut tästä...

Jos kuitenkin innostut kyhäilemään jonkinlaisia lisäosia, kannattaa olla niistä yhteydessä minuun (sähköposti sivun alalaidassa). Kuulen innolla ideoista ja ajatuksista!