Lingara Lingara Dokumentasi Panduan API Pustaka Aplikasi Buat Sematkan Aplikasi web
Bahasa: Bahasa Indonesia

Widget situs web

Halaman ini diterjemahkan dari bahasa Inggris. Jika keduanya berbeda, halaman bahasa Inggris yang benar. Baca halaman bahasa Inggris

Di situs web, Lingara berjalan sebagai elemen kustom, <lingara-embed>. Elemen itu menggambar latihan Lingara dalam frame yang disajikan oleh Lingara, sehingga halaman Anda tidak pernah melihat data pelajar dan halaman Lingara tidak pernah melihat data Anda.

Pasang elemen

Instal @lingara/embed dari npm, atau muat build modulnya dari CDN jika situs Anda tidak memiliki bundler. Lalu letakkan <lingara-embed> di halaman dan definisikan. Elemen itu menerima:

  • plan-id, rencana pelajaran yang akan dilatih, yang dimiliki pemain;
  • surface, apa yang ditampilkan: practice, bawaan dan satu-satunya surface yang ada;
  • theme, salah satu dari light, dark, atau auto;
  • locale, bahasa untuk kata-kata frame itu sendiri, yang jika tidak diatur mengikuti pelajar;
  • title, nama aksesibel frame.

Penataan gaya berhenti pada tema. Halaman Anda tidak dapat menjangkau ke dalam frame, dan tema adalah satu-satunya pengaturan yang ditawarkannya.

Berikan token

Atur tokenProvider elemen ke fungsi yang meminta token ke server Anda sendiri. Server Anda mencetaknya dengan origin halaman, menggunakan kit server, dan menjawab dengan token beserta waktu kedaluwarsanya. Elemen menyerahkan token ke frame melalui pesan, dan token tidak pernah berpindah lewat URL.

Daftarkan setiap origin tempat widget berjalan sebelum Anda mencetak token untuknya, di pengaturan klien Anda di konsol. Halaman kit server menjelaskan caranya. API menolak token yang dicetak untuk origin lain mana pun, dan frame menampilkan error alih-alih latihan.

Kit server juga dapat menulis seluruh snippet untuk Anda, elemen dan penyedia token sekaligus, dengan nonce skrip halaman Anda jika kebijakan keamanan konten Anda membutuhkannya. Contoh terakhir di bawah menunjukkannya.

Dengarkan apa yang dikatakan frame

Frame berkomunikasi dengan elemen melalui protokol pesan berversi, dan elemen mengubah apa yang dibutuhkan halaman Anda menjadi event DOM:

  • lingara:practice-completed saat pelajar menyelesaikan satu set, dengan planId, setNumber, correct, dan total set itu;
  • lingara:error saat frame berhenti, dengan sebuah code dan retryable. Error yang dapat dicoba ulang berarti pemasangan baru mungkin berhasil; kapan mencoba lagi, Anda yang menentukan.

Hasil latihan juga sampai ke server Anda, seperti yang dijelaskan di hasil latihan.

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)
})
Bahasa contoh kode

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();