İçeriğe geç

Olaylar ve mesaj protokolü

Widget, iframe içinden üst sayfaya mesaj gönderir; widget.js bunları kapsayıcı öğe üzerinde kabarcıklanan (bubbling) CustomEvent’lere çevirir. Böylece sonuçları kendi arayüzünüzde kullanabilir, analitik gönderebilir veya hataları izleyebilirsiniz.

Olay detail Ne zaman
mo:ready { id, height, tool, title, features } Widget yüklendi ve çizildi (bir kez; iframe yeniden yüklenirse tekrar).
mo:resize { id, height } İçerik yüksekliği değişti.
mo:input { id, field, inputs } Kullanıcı bir girdiyi düzenledi (250 ms geciktirilmiş). Yalnızca hesaplayıcı.
mo:result { id, data: { result, breakdown }, meta, inputs, requestId } Başarılı bir hesaplamadan sonra.
mo:error { id, error: { code, message, fields? }, requestId } Hesaplama başarısız olduğunda.
mo:select { id, kind, key, title, url } Arama/kategori widget’ında bir araç veya kategori seçildiğinde.
  • id, yükleyicinin bu widget örneğine atadığı kimliktir.
  • mo:ready içinde tool hesaplayıcı widget’ında { key, version, title }, diğer türlerde (ve eski embed sayfalarında) null’dır; title iframe’in güncel başlığıdır; features embed sayfasının yetenekleridir (config, inputs, calculate, reset, input-events).
  • mo:input içinde inputs, form geçerliyse isteğe giden kanonik girdilerdir, değilse null. field kullanıcının düzenlediği alanın adıdır.
  • mo:result içinde data ve meta, hesaplama yanıtıyla aynı biçimdedir; inputs hesaplamanın istek girdileridir. requestId, sonucun sizin calculate() çağrınıza yanıt olması durumunda doludur, aksi halde null.
  • mo:error içinde error.fields, doğrulama hatalarında [{ field, reason }] listesidir. requestId aynı mantıkla doludur.
  • mo:select: kind tool veya category, key seçilenin anahtarı, title başlığı, url hedef adrestir. Ayrıntı: Widget türleri.
const container = document.querySelector('[data-mo-tool="kdv"]');
container.addEventListener('mo:ready', (event) => {
console.log('Hazır:', event.detail.tool?.title, event.detail.features);
});
container.addEventListener('mo:input', (event) => {
// form geçerliyse event.detail.inputs dolu olur
console.log(event.detail.field, event.detail.inputs);
});
container.addEventListener('mo:result', (event) => {
const { data, meta, inputs } = event.detail;
console.log('Brüt tutar:', data.result.gross, '· araç sürümü', meta.toolVersion, '· girdiler', inputs);
});
container.addEventListener('mo:error', (event) => {
console.warn('Hesaplama hatası:', event.detail.error.code, event.detail.error.fields);
});

Olaylar kabarcıklandığı için sayfadaki tüm widget’ları tek yerden de dinleyebilirsiniz:

document.addEventListener('mo:result', (event) => {
// event.target: ilgili kapsayıcı öğe
analytics.track('calculation', { tool: event.target.dataset.moTool, id: event.detail.id });
});

mo:ready ve mo:resize için yükleyici iframe yüksekliğini de ayarlar (120–10000 px arası) ve son ölçülen yüksekliği hatırlar. Sizin ayrıca yükseklik yönetmenize gerek yoktur.

error.code, ya API hata kodlarından biridir (VALIDATION_ERROR, RATE_LIMITED, CALCULATION_ERROR, …) ya da API’ye ulaşılamadığında yerel bir koddur:

Kod Anlamı
NETWORK_ERROR API’ye bağlanılamadı.
TIMEOUT İstek zaman aşımına uğradı.
INVALID_RESPONSE Yanıt beklenen sözleşmeye uymuyor.

calculate() çağrıları ayrıca yükleyici tarafında NOT_MOUNTED, NOT_READY, UNSUPPORTED, TIMEOUT ve UNMOUNTED kodlarıyla reddedilebilir: JavaScript API.

error.message, widget’ın kullanıcıya kendisinin gösterdiği yerelleştirilmiş metindir; kendi arayüzünüzde mantığı code üzerine kurun.

Düz iframe kullanıyorsanız veya yükleyiciyi kullanmadan kendiniz dinlemek istiyorsanız, embed sayfası üst pencereye şu biçimde mesaj gönderir (targetOrigin: '*'):

{ source: 'mirac-ozdemir-widget', version: 1, id, type, ...payload }
type Payload Ne zaman
ready { height, tool: { key, version, title }, features: string[] } (arama/kategori için tool yerine kind) Hidrasyondan sonra bir kez.
resize { height } Belge yüksekliği her değiştiğinde (tamsayı CSS px).
input { field, inputs } Kullanıcı düzenlemesinden sonra (250 ms geciktirilmiş); form geçerli değilse inputs null.
result { data: { result, breakdown }, meta, inputs, requestId? } Her başarılı hesaplamadan sonra. requestId, bir calculate komutuna yanıt olduğunda gelir.
error { error: { code, message, fields? }, requestId? } Hesaplama isteği başarısız olduğunda.
select { kind: 'tool' | 'category', key, title, url } Yalnızca arama/kategori sayfaları.
  • id, adres satırındaki id parametresinin aynen geri gönderilmiş halidir ([A-Za-z0-9_-], 1–64). Parametre verilmediyse nulldır.
  • source ve version alanları, zarfın değişmez parçalarıdır; yük (payload) bunları ezemez.
  • Yükseklik her zaman yukarı yuvarlanmış tamsayıdır (içerik kırpılmaz).
  • v1 içinde yeni mesaj türleri ve yük alanları eklenebilir; bilmediklerinizi yok sayın (sürüm politikası).
window.addEventListener('message', (event) => {
if (event.origin !== 'https://mirac-ozdemir.com') return; // 1) gönderen origin
if (event.source !== iframe.contentWindow) return; // 2) beklediğiniz iframe
const m = event.data;
if (!m || m.source !== 'mirac-ozdemir-widget' || m.version !== 1) return; // 3) zarf
// m.type ve yükü artık güvenle kullanılabilir
});

widget.js bu üç kontrolü ve ayrıca id’nin bilinen bir örneğe ait olması kuralını kendisi uygular: sayfadaki bir çerçeve, başka bir widget’ı yeniden boyutlandıramaz veya taklit edemez. Mesajların yükü yükleyici tarafından asla DOM’a eklenmez, yalnızca olay detail’i olarak iletilir. Siz de yükteki metinleri sayfanıza eklerken textContent kullanın.

Ters yönde (sayfanız → embed) mesajlar şu zarfı kullanır ve iframe penceresine, targetOrigin olarak site origin’iyle gönderilir:

{ source: 'mirac-ozdemir-widget-host', version: 1, id, type, ...payload }
type Payload Etki
config { theme?, header?, density?, accent?, radius?, view? } Yalnızca sunum; canlı uygulanır.
inputs { values, autorun? } Girdileri doldurur (i.<alan> ile aynı temizleme kuralları).
calculate { requestId } Formu doğrular ve hesaplar; result veya error mesajı aynı requestId ile yanıtlar.
reset {} Formu sıfırlar.

Embed sayfası bir komutu yalnızca event.source === window.parent, zarf geçerli ve id kendi id’sine eşitse (asla null değil) kabul eder; bilinmeyen türler yok sayılır. Hangi komutların desteklendiği ready mesajındaki features alanındadır (config, inputs, calculate, reset). Yükleyiciyi kullanıyorsanız bunları elle göndermenize gerek yoktur: update, setInputs, calculate, reset bu mesajları sizin için üretir (JavaScript API).

document.addEventListener('mo:result', (event) => {
const { result } = event.detail.data;
document.querySelector('#ozet').textContent = `Brüt: ${result.gross} TRY`;
});