Dokumentacja techniczna komponentów interaktywnych

Wprowadzenie

Dokumentacja opisuje techniczne zagadnienia związane z tworzeniem własnych komponentów interaktywnych.

Przed utworzeniem własnego komponentu należy zarezerwować nazwę w systemie. Nazwa składa się z dwóch członów oddzielonych znakiem slash: nazwa przestrzeni/kod silnika (np. core/geogebra).

Po zarezerwowaniu nazwy, system utworzy repozytorium GIT do którego należy wgrać potrzebne pliki. System rozpocznie budowanie silnika, po otrzymaniu commita.

Wymagania techniczne

Kod silnika musi być zgodny z ECMAScript5. Wszystkie pliki tekstowe muszą być zakodowane w UTF-8 bez sygnatury BOM.

W dokumentacji użyto słowa kluczowego async (jest częścią ECMAScript6). Oznacza ono że dana metoda może zwrócić obietnicę Promise (nie musi).
Jeśli przy tworzeniu komponentu, używane są nowoczesne struktury składniowe, kod musi zostać skompilowany do składni ECMAScript5 (np. przy użyciu komilatora babeljs).

Architektura silnika

Silnik jest aplikacją zgodną z interfejsem platformy. Aby uruchomić silnik, należy utowrzyć instancję.

Musi zawierać plik engine.json oraz plik wejścia.

Definicja silnika - engine.json

Plik engine.json definiuje jakie funkcje dostarcza oraz jakich funkcji wymaga komponent.

Włączenie niektórych opcji, może nieść za sobą konieczność implementacji dodatkowych metod.

Minimalna (wymagana) zawartość pliku:

{
  "entry": "entry.js",
}

Wszystkie opcje

{
  "entry": "entry.js",
  "stateful": true | false,
  "isolation": "shadow" | "iframe" | "none",
  "validation": "auto" | "manual" | "none",
  "editor": {
    "entry": "editorEntry.js",
    "defaultData": {},
    "demoData": {}
  }
}

Funkcje poszczególnych pól:

Punkt wejścia (entry)

Dostarczany jest w formie asynchronicznego modułu AMD lub kompatybilnego (np UMD). Synchroniczne żądanie bibliotek jest niedozwolone.

Moduł musi eksportować fabrykę (funkcję która utworzy silnik) lub konstruktor.

Przykłady eksportu fabryki (moduł AMD):

define([], function() {
    return function() {
        return {
            init: function() {},
            destroy: function() {}
        }
    }
})  

Przykłady eksportu konstruktora (moduł AMD):

define([], function() {
    function Engine() {}
    
    Engine.prototype.init: function() {},
    Engine.prototype.destroy: function() {}
    
    return Engine;
})

Przykłady eksportu fabryki (moduł AMD) z żądaniem biblioteki jQuery:

define(['jquery'], function($) {
    return function() {
        return {
            init: function() {},
            destroy: function() {}
        }
    }
})  

Biblioteki współdzielone

Jeśli istnieje potrzeba użycia innych popularnym frameworków, prosimy o kontakt z administracją portalu.

Interfejs silnika

Bazowy interfejs silnika. Implementacja tego interfejsu jest zawsze wymagana.

{
    async init(container, api, options)
    destroy(container)
}

Stateful

Po zmiane stanu, komponent powinien wywołać metodę API triggerStateSave(). System wkrótce wywoła metodę getState(). Zwrócona wartość zostanie zapisana.

{
    setState(stateData)
    getState()
    setStateFrozen(isFrozen)
}

Validation

Wymaga implementacji interfejsu stateful.

{
    isStateValid(stateData)
}

API

Obiekt API jest przekazywany w metodzie init. Umożliwia on komunikację z systemem.

{
    triggerStateSave();
    triggerStateRestore();
    enginePath(path);
    dataPath(path);
    async loadCss(realPath);
}

Instancja komponentu

Gotowy silnik można wykorzystać, tworząc instancję komponentu.

Komponent składa się z pliku manifest.json oraz innych plików z których korzysta silnik, a które są specyficzne dla danej instancji.

Struktura pliku manifest.json

{
    "engine": "nazwa przestrzeni/kod silnika",
    "data": {...}
}

Wszystkie pliki powinny zostać spakowane do formatu ZIP. Plik manifest.json musi znajdować się na samym szycie struktury archiwum (nie może znajdować się w żadnym katalogu).

Bezpieczeństwo

Warunkiem koniecznym jest, aby silnik nie pozwalał na wykonanie obcego kodu lub zpreparowanych żądań.

Jeśli silnik ma zostać udostępniony osobom trzecim, konieczne jest aby dodatkowo filtrował wszystkie dane przekazane w pliku manifest.json.