Доста често напоследък ми се налага да правя динамични страници изцяло задвижвани от javascript, като при тях постоянно се добавят и махат dom елементи. Което значи непрекъснато да се добавят и махат event хандлъри, което е меко казано досадно и води до много грешки. Но с вградените в CD3.Behaviors event delegation функции (за тях специално ще има поне един цял пост) тази работа е много лесна, просто делегирам всички действия към елементи които няма да се променят.
До тук всичко звучи много добре, но както винаги IE се появява на сцената с бъг, който е, че submit действието няма bubbling (т.е. не се делегира към родителските елементи на формата). Което е в пълен разрез със спецификация, но какво да се прави свикнали сме.
Този проблем го знам от много време и винаги го заобикалях по един или друг начин. Но наскоро на колега му трябваше бързо решение, което да може да ползва на 2 – 3 места затова за няколко минути написах това за Prototype.js:
Element.addMethods({
delegateSubmit: function(element, callback){
return $(element)
.observe('click', function(e){
if (e.findElement('form') && e.findElement('input[type=submit],input[type=image]'))
callback.call(this, e);
})
.observe('keyup', function(e){
if (e.keyCode == Event.KEY_RETURN && e.findElement('input') && e.findElement('form'))
callback.call(this, e);
})
}
});
Като цяло това, което прави тази функция е, че наблюдава за натискане на submit или image бутони или за натискане на enter върху някои input. Лошото в случая е, че страдат и нормалните браузъри като Firefox или Safari.
Затова направих нова версия, която засича дали submit се делегира (за начина, по който разбирам пише по-подробно в тази статия – Detecting event support without browser sniffing)
Element.addMethods({
delegateSubmit: (function(){
var el = document.createElement('div'), isSupported = 'onsubmit' in el;
if (!isSupported){
el.setAttribute('onsubmit', 'return;');
isSupported = typeof el.onsubmit == 'function';
}
return isSupported ? function(element, callback){
return Event.observe(element, 'submit', callback);
} : function(element, callback){
return $(element)
.observe('click', function(e){
if (e.findElement('form') && e.findElement('input[type=submit],input[type=image]'))
callback.call(this, e);
})
.observe('keyup', function(e){
if (e.keyCode == Event.KEY_RETURN && e.findElement('input') && e.findElement('form'))
callback.call(this, e);
})
};
})()
});
Това е доста по-добро решение което оправя проблема със submit само, когато има такъв проблем.
Тук бих могъл примерно да използвам Function.wrap върху Event.observe, но нещо не съм фен такива monkey patching неща. А и по-скоро това и хака за делегиране на focus/blur под IE ще са част от моята Event.delegate, която ако имам късмет ще е част от Prototype.js.
Ако някой има по-елегантно решение, няма да му се разсърдя ако го сподели.


