Ders 04 / 24
Varsayılan Davranış ve İptal
Tarayıcının olaylara verdiği yerleşik yanıt ve onu iptal etme isteği; iptal edilebilirlik koşulu, iptalin yayılımı durdurmakla karışmaması, edilgen dinleyicinin kısıtı ve iptalin ne zaman meşru olduğu.
İçindekiler
Önceki derslerde dinleyiciler yalnızca ekledi: olay geldi, kod çalıştı, sayfaya bir davranış katıldı. Oysa tarayıcının kendi davranışları da vardır ve hiçbir dinleyici olmadan işlerler. Bağlantıya tıklamak gezinme başlatır, gönderim düğmesi formu gönderir, onay kutusu işaretini değiştirir, boşluk tuşu sayfayı kaydırır.
Bir dinleyici bu davranışların yerine kendi davranışını koymak istediğinde, tarayıcının yapacağı işi iptal etmesi gerekir. Bu ders iptalin nasıl istendiğini, hangi koşullarda kabul edildiğini ve neden yayılımı durdurmakla aynı şey olmadığını kurar.
Varsayılan Eylem
Bir olayın varsayılan eylemi (default action), tarayıcının o olaya verdiği yerleşik yanıttır. Belgede yazılı değildir, biçemde de değildir; işaretlemenin anlamından gelir. Bağlantı ögesinin anlamı “başka bir kaynağa götürür” olduğu için tıklandığında gezinme başlar. Gönderim düğmesinin anlamı “formu gönderir” olduğu için tıklandığında giriş listesi hazırlanır.
Varsayılan eylemin iki özelliği kritiktir.
Birincisi sırasıdır. Varsayılan eylem, olayın yayılımı bittikten sonra çalışır. Yayılım yolundaki herhangi bir dinleyici — hedeftekiler kadar atalardakiler de — eylemi iptal edebilir. Ata düğümün kabarcık evresindeki dinleyicisi, hedefte başlamış bir gezinmeyi durdurabilir.
İkincisi zincirlenebilirliğidir. Bazı varsayılan eylemler yeni bir olay üretir. Bir etikete tıklamak, bağlı olduğu form alanında bir tıklama olayı doğurur; o tıklamanın da kendi varsayılan eylemi vardır. Bu nedenle tek bir kullanıcı hareketi birden çok olay ve birden çok varsayılan eylem üretebilir; zincirin hangi halkasında iptal edildiği sonucu belirler.
İptal İsteği
Dinleyici, olay nesnesi üzerinden iptal ister. İstek her zaman kabul edilmez: olayın iptal edilebilir (cancelable) olması gerekir. Kaydırma bildirimi gibi bazı olaylar tarayıcı işi zaten yaptıktan sonra üretilir ve iptal edilemez; istek sessizce yok sayılır.
// varsayilan.mjs — yayilim, iptal ve varsayilan eylemin sirasi const oge = (ad, ...cocuklar) => { const d = { ad, cocuklar, ebeveyn: null, dinleyiciler: [] }; for (const c of cocuklar) c.ebeveyn = d; return d; }; const dinle = (dugum, etiket, eylem, edilgen = false) => dugum.dinleyiciler.push({ etiket, eylem, edilgen }); function yay(hedef, { tur, iptalEdilebilir, varsayilanEylem }) { const zincir = []; for (let d = hedef; d; d = d.ebeveyn) zincir.push(d); const olay = { tur, iptalEdilebilir, varsayilanOnlendi: false, durduruldu: false }; const gunluk = []; olay.varsayilaniOnle = function () { if (this.edilgenDinleyicide) return gunluk.push(" [yok sayildi] edilgen dinleyici"); if (olay.iptalEdilebilir === false) return gunluk.push(" [yok sayildi] iptal edilemeyen olay"); olay.varsayilanOnlendi = true; }; for (const dugum of zincir) { // kabarcik evresi: hedeften koke if (olay.durduruldu) break; for (const d of dugum.dinleyiciler) { olay.edilgenDinleyicide = d.edilgen; gunluk.push(` ${dugum.ad}/${d.etiket} (onlendi=${olay.varsayilanOnlendi})`); d.eylem?.(olay); } } gunluk.push(olay.varsayilanOnlendi ? ` varsayilan eylem: iptal` : ` varsayilan eylem: ${varsayilanEylem}`); return gunluk; } function agac(dinleyiciKur) { const bag = oge("a"); const gezinti = oge("nav", bag); oge("main", gezinti); dinleyiciKur(bag, gezinti); return bag; } const TIKLAMA = { tur: "click", iptalEdilebilir: true, varsayilanEylem: "gezinme" }; const durumlar = [ ["engelsiz", TIKLAMA, (bag, nav) => { dinle(bag, "bag"); dinle(nav, "nav"); }], ["varsayilaniOnle", TIKLAMA, (bag, nav) => { dinle(bag, "bag", (o) => o.varsayilaniOnle()); dinle(nav, "nav"); }], ["stopPropagation", TIKLAMA, (bag, nav) => { dinle(bag, "bag", (o) => { o.durduruldu = true; }); dinle(nav, "nav"); }], ["iptal edilemeyen olay", { tur: "scroll", iptalEdilebilir: false, varsayilanEylem: "kaydirma" }, (bag) => { dinle(bag, "bag", (o) => o.varsayilaniOnle()); }], ["edilgen dinleyici", { tur: "wheel", iptalEdilebilir: true, varsayilanEylem: "kaydirma" }, (bag) => { dinle(bag, "bag", (o) => o.varsayilaniOnle(), true); }], ]; for (const [ad, olayTanimi, kur] of durumlar) { console.log(ad); for (const satir of yay(agac(kur), olayTanimi)) console.log(satir); }
engelsiz a/bag (onlendi=false) nav/nav (onlendi=false) varsayilan eylem: gezinme varsayilaniOnle a/bag (onlendi=false) nav/nav (onlendi=true) varsayilan eylem: iptal stopPropagation a/bag (onlendi=false) varsayilan eylem: gezinme iptal edilemeyen olay a/bag (onlendi=false) [yok sayildi] iptal edilemeyen olay varsayilan eylem: kaydirma edilgen dinleyici a/bag (onlendi=false) [yok sayildi] edilgen dinleyici varsayilan eylem: kaydirma
İkinci durumda hedefteki dinleyici iptal ister; olay yoluna devam eder ve ata düğümdeki
dinleyici onlendi=true değerini okur. Tarayıcı API’sinde bu bayrağın adı
defaultPrevented tir. Yayılımın devam etmesi bir kusur değil, tasarımın kendisidir: yol
üzerindeki sonraki dinleyiciler kararı görebilir ve kendi davranışlarını ona göre
ayarlayabilir.
İptal ile Durdurmayı Ayırmak
Üçüncü durum bu dersin en sık karıştırılan noktasını gösterir. Yayılım durdurulmuştur — ata dinleyicisi hiç çağrılmamıştır — ama gezinme yine de olmuştur.
İki işlem birbirinden bağımsızdır:
- Yayılımı durdurmak, olayın başka dinleyicilere ulaşmasını engeller. Tarayıcının kendi davranışına dokunmaz.
- İptal istemek, tarayıcının davranışını engeller. Olayın yoluna devam etmesini engellemez.
Buradan iki yanlış çıkar. Birincisi, gezinmeyi durdurmak isteyip yayılımı durduran kod gezinmeyi durduramaz. İkincisi, yalnızca kendi işini yapmak isteyip iptal ile birlikte yayılımı da durduran kod, sayfanın başka yerlerindeki devredilmiş dinleyicileri sessizce devre dışı bırakır. İki işlem ayrı ayrı istenmelidir ve çoğu durumda yalnızca biri gereklidir.
Edilgen Dinleyici
Son durum farklı bir kısıt gösterir. Kaydırma ile ilgili olaylarda tarayıcı bir ikilemle karşılaşır: dinleyici iptal edebilir mi, edemez mi bilmeden kaydırmayı başlatamaz. Bu nedenle dinleyicinin bitmesini bekler; uzun süren bir dinleyici parmağın altındaki sayfayı bekletir.
Edilgen dinleyici (passive listener) bu belirsizliği kaldırır. Kayıt sırasında verilen bir seçenekle dinleyici “iptal istemeyeceğim” diye bildirir; tarayıcı kaydırmayı dinleyiciyi beklemeden başlatır. Bildirime aykırı olarak iptal istenirse istek yok sayılır.
Buradan pratik bir kural çıkar: kaydırmayı gözleyen ama değiştirmeyen dinleyiciler edilgen kaydedilir. Kaydırmanın yerine kendi davranışını koyan bir dinleyici edilgen olamaz ve bekletme maliyetini kabul eder.
İptalin İnce Noktaları
Bazı olaylarda iptal, izin anlamına gelir. Sürükle bırak işleminde bir ögenin üzerinden geçilirken üretilen olayın varsayılan eylemi “bırakmayı reddet” tir; iptal edilmediği sürece bırakma gerçekleşmez. Burada iptal istemek davranışı engellemez, tersine açar. Bu nedenle “iptal her zaman engellemektir” varsayımı yanlıştır; her olayın varsayılan eyleminin ne olduğu ayrıca bilinmelidir.
İptal, durumu geri almayabilir. Onay kutusuna tıklandığında işaret değişimi olay yayılmadan önce yapılır; iptal, değişimi geri alır. Dinleyici içinde okunan güncel değer bu nedenle iptalden sonra geçerli olmayabilir.
İptal edilmiş bir eylemin yerine bir şey konmalıdır. Formun gönderimini iptal edip veriyi kendi kodunda gönderen bir sayfa doğru davranır. Gönderimi iptal edip yerine hiçbir şey koymayan sayfa, kullanıcının işini görünür bir neden olmadan bitirir. Aynı ilke bağlantılar için de geçerlidir: gezinmeyi iptal eden kod, kullanıcının orta tuşla yeni sekmede açma, adresi kopyalama ve bağlantının nereye gittiğini görme olanağını da elinden alır.
Klavye ve erişilebilirlik davranışları iptal edilmez. Sekme tuşunun odak taşıma davranışını iptal eden bir sayfa, klavyeyle kullanılamaz hâle gelir. Aynı biçimde metin seçimini, sağ tuş menüsünü ve yakınlaştırmayı iptal etmek, kullanıcının denetimini kaldırır. Bu davranışlar ancak yerlerine eşdeğer bir yol konduğunda iptal edilir; bunun sınırları Odak ve Klavye Etkileşimi dersinde belirlenir.
İptalin Geri Alınamaması
Bayrağın okunabilir olması, değiştirilebilir olduğu anlamına gelmez. İptali geri alan bir işlem yoktur. Yol üzerindeki ilk iptal isteği kararı kesinleştirir; sonraki dinleyiciler yalnızca kararı görür.
Bunun tasarım sonucu şudur: iptal kararını, davranışın sahibi olan dinleyici vermelidir. Ölçüm formunun gönderimini iptal edecek kod formun kendi dinleyicisidir; forma dışarıdan bakan genel bir dinleyicinin kararı, formun kendi mantığını görmeden verilmiş olur.
Aynı kesinlik ters yönde de geçerlidir. Bir dinleyici yayılımın erken bir noktasında koşulsuz iptal isterse, sonraki dinleyicilerin davranışı geri getirmesi mümkün değildir; tek çare iptal koşulunu o dinleyicinin içine taşımaktır. Koşul dışarıda kaldıkça iptal, davranışı sessizce ve kalıcı olarak kapatan bir anahtara dönüşür.
Sayfadan ayrılma bu kuralın en görünür örneğidir. Kaydedilmemiş değişikliği olan bir sayfa, ayrılma öncesinde üretilen olayı iptal ederek tarayıcıdan onay istemesini sağlayabilir. Onayın metnini ve biçimini sayfa belirlemez; tarayıcı belirler ve genellikle kullanıcının sayfayla önceden etkileşmiş olmasını koşul sayar. Kural aynıdır: iptal isteği bir öneridir, tarayıcının kabul koşulları dışında karşılık bulmaz.
Özet
- Varsayılan eylem, tarayıcının bir olaya verdiği ve işaretlemenin anlamından gelen yerleşik yanıttır; yayılım bittikten sonra çalışır.
- Yayılım yolundaki her dinleyici iptal isteyebilir; iptal isteği yalnızca olay iptal edilebilir olduğunda kabul edilir, aksi durumda sessizce yok sayılır.
- İptal ile yayılımı durdurmak bağımsız işlemlerdir: biri tarayıcının davranışını, diğeri olayın diğer dinleyicilere ulaşmasını engeller.
- İptal edildikten sonra da olay yoluna devam eder; sonraki dinleyiciler kararı bir bayrak üzerinden okuyabilir ama geri alamaz.
- Edilgen dinleyici iptal istemeyeceğini önceden bildirir; tarayıcı kaydırmayı beklemeden başlatır ve aykırı istek yok sayılır.
- Bazı olaylarda iptal engelleme değil izin anlamına gelir; iptal edilen her davranışın yerine eşdeğer bir yol konmalıdır.
Sonraki Adım
Bu ders, iptal edilmemesi gereken davranışlar arasında klavyeyi ayrı tuttu ve gerekçeyi sonraya bıraktı. Gerekçe şudur: sayfayla etkileşimin tamamı işaretleme aygıtıyla kurulmaz. Kullanıcı sekme tuşuyla ögeler arasında dolaşır, boşlukla düğmeye basar, ok tuşlarıyla seçenekler arasında geçer; ekran okuyucu da aynı yolu izler. Bu dolaşımın merkezinde tek bir kavram vardır: belgede her an en çok bir öge girdiyi alır. Sonraki ders bu ögenin nasıl belirlendiğini, sıranın neye göre kurulduğunu ve klavye olaylarının hangi bilgiyi taşıdığını inceler.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.