Lingara Lingara Dokumentasi Panduan API Pustaka Aplikasi Bina Benam Apl web
Bahasa: Bahasa Melayu

Widget laman web

Halaman ini diterjemahkan daripada bahasa Inggeris. Jika kedua-duanya berbeza, halaman bahasa Inggeris adalah yang betul. Baca halaman bahasa Inggeris

Di laman web, Lingara berjalan sebagai elemen tersuai, <lingara-embed>. Elemen itu melukis latihan Lingara dalam bingkai yang disajikan oleh Lingara, jadi halaman anda tidak pernah melihat data pelajar dan halaman Lingara tidak pernah melihat data anda.

Pasang elemen

Pasang @lingara/embed daripada npm, atau muatkan binaan modulnya daripada CDN jika laman anda tiada bundler. Kemudian letakkan <lingara-embed> pada halaman dan takrifkannya. Elemen itu mengambil:

  • plan-id, pelan pelajaran untuk dilatih, yang dimiliki oleh pemain;
  • surface, apa yang hendak dipaparkan: practice, lalai dan satu-satunya permukaan yang ada;
  • theme, salah satu daripada light, dark atau auto;
  • locale, bahasa bagi perkataan bingkai itu sendiri, yang jika tidak ditetapkan mengikut pelajar;
  • title, nama boleh akses bingkai.

Penggayaan terhenti pada tema. Halaman anda tidak boleh mencapai ke dalam bingkai, dan tema ialah satu-satunya tetapan yang ditawarkannya.

Berikannya token

Tetapkan tokenProvider elemen kepada fungsi yang meminta token daripada pelayan anda sendiri. Pelayan anda mencetaknya dengan asalan halaman, menggunakan kit pelayan, dan menjawab dengan token serta tempoh tamatnya. Elemen menyerahkan token kepada bingkai melalui mesej, dan token tidak pernah bergerak dalam URL.

Daftarkan setiap asalan tempat widget berjalan sebelum anda mencetak untuknya, dalam tetapan klien anda dalam konsol. Halaman kit pelayan menerangkan caranya. API menolak token yang dicetak untuk mana-mana asalan lain, dan bingkai memaparkan ralat dan bukannya latihan.

Kit pelayan juga boleh menulis keseluruhan snippet untuk anda, elemen dan penyedia token bersama-sama, dengan nonce skrip halaman anda jika dasar keselamatan kandungan anda memerlukannya. Sampel terakhir di bawah menunjukkannya.

Dengar apa yang dikatakan oleh bingkai

Bingkai bercakap dengan elemen melalui protokol mesej berversi, dan elemen menukar apa yang diperlukan oleh halaman anda menjadi acara DOM:

  • lingara:practice-completed apabila pelajar menyelesaikan satu set, dengan planId, setNumber, correct dan total set itu;
  • lingara:error apabila bingkai berhenti, dengan code dan retryable. Ralat yang boleh dicuba semula bermakna pemasangan baharu mungkin berjaya; bila hendak mencuba lagi terpulang kepada anda.

Hasil latihan juga sampai ke pelayan anda, seperti yang diterangkan dalam 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 kod

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