Lingara Lingara Ohjeet Oppaat API Kirjastot Sovellukset Rakenna Upotus Verkkosovellus
Kieli: Suomi

Verkkosivuston widget

Tämä sivu on käännetty englannista. Jos ne eroavat toisistaan, englanninkielinen sivu on oikea. Lue englanninkielinen sivu

Verkkosivustolla Lingara toimii mukautettuna elementtinä, <lingara-embed>. Elementti piirtää Lingaran harjoittelun kehykseen, jonka Lingara tarjoilee, joten sivusi ei koskaan näe oppijan tietoja eikä Lingaran sivu koskaan näe sinun tietojasi.

Liitä elementti

Asenna @lingara/embed npm:stä tai lataa sen moduulikoontiversio CDN:stä, jos sivustollasi ei ole bundleria. Lisää sitten <lingara-embed> sivulle ja määrittele se. Elementti ottaa:

  • plan-id, harjoiteltava tuntisuunnitelma, jonka pelaaja omistaa;
  • surface, mitä näytetään: practice, oletus ja ainoa olemassa oleva näkymä;
  • theme, yksi arvoista light, dark tai auto;
  • locale, kehyksen omien tekstien kieli, joka muuten seuraa oppijaa;
  • title, kehyksen saavutettava nimi.

Tyylittely rajoittuu teemaan. Sivusi ei pääse kehyksen sisään, ja teema on ainoa asetus, jonka se tarjoaa.

Anna sille tunnukset

Aseta elementin tokenProvider funktioksi, joka pyytää tunnusta omalta palvelimeltasi. Palvelimesi luo sen sivun alkuperälle palvelinpaketilla ja vastaa tunnuksella ja sen vanhenemisajalla. Elementti luovuttaa tunnuksen kehykselle viestinä, eikä tunnus koskaan kulje URL-osoitteessa.

Rekisteröi jokainen alkuperä, jossa widget toimii, ennen kuin luot tunnuksia sille, asiakkaasi asetuksissa konsolissa. Palvelinpakettien sivu kertoo miten. API hylkää minkä tahansa muulle alkuperälle luodun tunnuksen, ja kehys näyttää virheen harjoittelun sijaan.

Palvelinpaketti voi myös kirjoittaa koko koodinpätkän puolestasi, elementin ja tunnuksen tarjoajan yhdessä, sivusi skriptin noncen kanssa, jos sisällön suojauskäytäntösi sellaista tarvitsee. Viimeinen alla oleva esimerkki näyttää sen.

Kuuntele, mitä kehys kertoo

Kehys viestii elementin kanssa versioidulla viestiprotokollalla, ja elementti muuttaa sen, mitä sivusi tarvitsee, DOM-tapahtumiksi:

  • lingara:practice-completed, kun oppija suorittaa sarjan, kentillä planId, setNumber, correct ja total;
  • lingara:error, kun kehys pysähtyy, kentillä code ja retryable. Uudelleenyritettävä virhe tarkoittaa, että uusi liittäminen voi onnistua; sen, milloin yrität uudelleen, päätät itse.

Myös harjoittelun tulos saapuu palvelimellesi, kuten kohdassa harjoittelun tulokset kuvataan.

npm install @lingara/embed@0.1.0-alpha.6
# No bundler? One module script instead:
# <script type="module" src="https://cdn.jsdelivr.net/npm/@lingara/embed@0.1.0-alpha.6/dist/lingara-embed.min.js"></script>
<!-- plan-id is a lesson plan your server made for this player. -->
<lingara-embed surface="practice" plan-id="0b9d4f2e-3c1a-4e8b-9f6d-2a7c5e1b8d40" theme="auto" title="Practice"></lingara-embed>
<script type="module">
  import { defineLingaraEmbed } from '@lingara/embed'
  defineLingaraEmbed()
</script>
// Your own endpoint, on your own server. It mints with this page's origin and
// returns exactly { token, expires_at }: the token (lgr_et_…) never touches a URL.
widget.tokenProvider = async () => {
  const response = await fetch('/lingara/token', { method: 'POST', credentials: 'same-origin' })
  if (!response.ok) throw new Error(`token endpoint answered ${response.status}`)
  return response.json()
}
widget.addEventListener('lingara:practice-completed', (event) => {
  const { planId, setNumber, correct, total } = (event as CustomEvent).detail
  console.log(`set ${setNumber} of ${planId}: ${correct}/${total}`)
})
widget.addEventListener('lingara:error', (event) => {
  const { code, retryable } = (event as CustomEvent).detail
  // `retryable` means a remount may succeed; when to try is yours to decide.
  if (retryable) setTimeout(() => widget.reload(), 30_000)
  else console.warn('Lingara practice stopped:', code)
})
Koodiesimerkin kieli

TypeScript

// The page that mounts the widget: the token never appears in it.
export function practicePage(planId: string, cspNonce: string): string {
  const widget = widgetSnippet({ planId, tokenEndpoint: '/lingara/token', theme: 'auto', locale: 'fr', title: 'Pratique', nonce: cspNonce })
  return `<!doctype html><title>Practice</title>${widget}`
}

Rust

// The element, its script build and a token provider that POSTs to your
// token route. The token never appears in the markup.
let html = widget_snippet(&SnippetOptions {
    locale: Some("fr".into()),
    nonce: Some(csp_nonce.into()), // your page's CSP nonce, for a strict script-src
    ..SnippetOptions::new(plan_id, "/lingara/token")
})?;

Go

// The plan your server made for this player, and the token route above.
// Pass the request's CSP nonce when your script-src allows no inline
// script; the token itself never appears in the markup.
theme := "auto"
html, err := lingaraembed.WidgetSnippet(lingaraembed.SnippetOptions{
	PlanID:        planID,
	TokenEndpoint: "/lingara/token",
	Theme:         &theme,
	Nonce:         &cspNonce,
})
if err != nil {
	return "", err // a *lingaraembed.SnippetError names the refused option
}
return template.HTML(html), nil // already escaped by the kit

Java

// planId is the lesson plan your server made for this player. The element
// POSTs to tokenEndpoint with same-origin cookies: the token never appears
// in the markup. Pass this request's CSP nonce if your page sets one.
String html =
    WidgetSnippet.render(
        SnippetOptions.builder(planId, "/lingara/token").locale("fr").nonce(cspNonce).build());

Kotlin

// planId is the lesson plan your server made for this player. The element
// POSTs to tokenEndpoint with same-origin cookies: the token never appears
// in the markup. Pass this request's CSP nonce if your page sets one.
val html =
    widgetSnippet(
        SnippetOptions(planId, tokenEndpoint = "/lingara/token").apply {
            locale = "fr"
            nonce = cspNonce
        },
    )

Ruby

# The plan your server made for this player, rendered into your page.
# nonce: your page's CSP nonce, when its script-src allows no inline script.
def self.widget(plan_id, csp_nonce)
  Lingara::Embed.widget_snippet(plan_id: plan_id, token_endpoint: "/lingara/token", locale: "fr", nonce: csp_nonce)
end

PHP

use Lingara\Embed\SnippetOptions;
use Lingara\Embed\WidgetSnippet;

// In your page's template: the plan your server made for this player, and
// your token route. Pass the request's CSP nonce if your script-src allows
// no inline script. A bad option throws SnippetException naming its field.
function practiceWidget(string $planId, string $cspNonce): string
{
    return WidgetSnippet::render(new SnippetOptions(
        planId: $planId,
        tokenEndpoint: '/lingara/token',
        theme: 'auto',
        nonce: $cspNonce,
    ));
}

C#

app.MapGet("/practice/{planId}", (string planId, HttpContext http) =>
{
    var widget = WidgetSnippet.Render(new SnippetOptions
    {
        PlanId = planId,                              // the plan your server made for this player
        TokenEndpoint = "/lingara/token",             // same origin: the element sends this page's cookies
        Nonce = http.Items["csp-nonce"] as string,     // your CSP's nonce, if script-src has one
    });
    return Results.Content($"<!doctype html><title>Practice</title>\n{widget}", "text/html");
}).RequireAuthorization();