B~Vladi,
я e1f'а процитирую, вдруг не заметил Цитата:
И зачем имена функций/методов с большой буквы? |
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
Цитата:
|
Цитата:
Я частенько к концу раб. дня могу тупить, так что не обращайте внимание:) По поводу того, как узнать, была ли ошибка... Я так понимаю, можно пойти 2 путями - где-то это всё сохранять (Event.errors, например) и уже самому смотреть, были ли ошибки... Или можно вызвать событие window.onerror... Вобщем, скажите хоть как будет правильнее а?! |
Вобщем, теперь сохраняю все ошибки в массив Event.errors (свойство библиотеки).
При генерировании нового события, массив обнуляется. Если передан обработчик onerror и возникает ошибка - он вызывается в контексте события и передаётся ошибка. Так пойдёт?! |
Честно говоря, я весь текущий спич слабо воспринимаю :) Если я пишу такой обработчик, который может упасть -- я заверну его в try/catch сам.
Onerror -- есть баги, выполнение скрипта-то все равно стопается. Насчет методов -- а почему не "первая буква маленькая, дальше заглавные большие"? JS-style, вроде бы ;) |
Ещё убрал строчку присваивания возвращаемого значения в событие...
Если необходимо передать что-либо в следующий обработчик - достаточно присвоить это в объект event. Цитата:
Цитата:
|
по поводу исключений: браузер как поступает? Просто пишет ошибку в журнал и выполняет следующий обработчик и всплытие не прекращается, так? (надо проверить). Вот так и сделай, журналом у тебя будет errors, причем он будет только для отладки использоваться. Т.е. чтобы его можно было отключить. p.s. если обработчик не озаботился обработкой ошибок - это его проблемы
Цитата:
Цитата:
p.s. еще посмотри фреймворки на предмет усовершенствований |
Цитата:
Цитата:
Цитата:
Да, поковырять можно немного... |
Цитата:
Цитата:
|
Ну, учитывая, что кусок с fixEvent взят явно из jQuery... ;)
|
Цитата:
Хотя я там target пофиксил;) Цитата:
Т.е. без него и try catch ловить не надо?! |
B~Vladi,
неа, это метод, который ты сам руками напишешь, и если Event.debug() == true, то мы работаем в режиме дебуг, со всякими вкусными, но бесполезными для пользователя плюхами, типа алерта стека вызовов :) |
Цитата:
Цитата:
|
а вообще можно попытаться придумать конкретную ситуацию, когда если ошибка происходит в одном обработчике, то другой обработчик (с ним связанный) не должен выполняться. Мне в голову ничего не приходит :-?
|
Цитата:
Цитата:
Цитата:
Если такого обработчика нет - :-? |
Добавил, значт, вот ещё что:
Event.Add(obj,'type',{handler:fnc,onerror:(bool||fnc)}) Здесь: onerror - если передаётся true - ошибка в обработчике не остановит вызов других. Если false - остановит. Если передаётся функция - обработчик ошибки и возвращает false - вызовы остановятся. Если ничего не передано - вызовы будут останавливаться. Так норм?! |
Цитата:
B~Vladi, т.е. предлагается в каждый обработчик каждого события добавлять код обработки ошибок, который по сути будет console.log, т.к. нам нужно только узнать об ошибке? |
Цитата:
Цитата:
Предлагается возможность обработать ошибку события самому, если это нужно. Если каждую ошибку обрабатывать не надо - можно установить свойство Debug для Event, передав туда код обработки. Этот Debug будет вызван в конце выполнения всех обработчиков. Если во время выполнения даётся указание прервать вызовы - Debug так же будет вызван, если есть ошибки. |
Цитата:
Цитата:
|
Цитата:
Просто я настолько хороший кодер, что на это закрывают глаза:D Цитата:
Цитата:
|
Kolyaj,
а стоит ли вообще с этим париться? Не скажется ли на производительности, если мы каждый обработчик будем совать try/catch, нужен он там или нет? Может, лучше я сам в обработчике и проверку сделаю, если надо? |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
|
Ну, если наш обработчик не использует никаких глобальных переменных, не опирается на приведение типов, все корректно проверяет -- как там может возникнуть ошибка? Заворачивать вызов каждой функции в try/cacth -- имхо не очень выход.
|
Цитата:
|
Цитата:
p.s. я бы из всего функционала реализовал бы только fixEvents. Не приходит в голову конкретных ситуаций, когда мне остальное может пригодиться |
Есть некоторые мысли. Да, действительно всё это лишнее. Как родится новый код - отпишусь.
|
Вобщем, координальных изменений нет...
Оптимизировал, поймал один баг, немного изименился вызов Add. Код: var Event=(function(){ var allList=new Array; var handler=function(evt,index){ if(!evt.fix){ if(!evt)evt=event; if(!evt.preventDefault)evt.preventDefault=function(){evt.returnValue=false;} if(!evt.stopPropagation)evt.stopPropagation=function(){evt.cancelBubble=true;} if(!evt.target)evt.target=(evt.srcElement.nodeType==1)?evt.srcElement:evt.srcElement.parentNode; if(!evt.relatedTarget&&evt.fromElement)evt.relatedTarget=(evt.fromElement==evt.target)?evt.toElement:evt.fromElement; if(!evt.which&&evt.button)evt.which=(evt.button&1?1:(evt.button&2?3:(evt.button&4?2:0))); if(evt.pageX==null&&evt.clientX!=null){ var html=document.documentElement,body=document.body; evt.pageX=evt.clientX+(html&&html.scrollLeft||body&&body.scrollLeft||0)-(html.clientLeft||0); evt.pageY=evt.clientY+(html&&html.scrollTop||body&&body.scrollTop||0)-(html.clientTop||0); } evt.fix=true; } for(var i in allList[index].list[evt.type]){ if(allList[index]&&allList[index].list[evt.type]&&allList[index].list[evt.type][i].call.call(this,evt,allList[index].list[evt.type][i].data)===false){ evt.stopPropagation(); evt.preventDefault(); break; } } } return{ Add:function(ele,type,call,data){ if(ele.setInterval&&(ele!=window&&!ele.frameElement))ele=window; for(var i in allList){ if(allList[i].ele==ele){ if(!allList[i].list[type]){ allList[i].list[type]=[{ call:call, data:obj.data }]; if(ele.addEventListener)ele.addEventListener(type,allList[i].listener,false); else if(ele.attachEvent)ele.attachEvent('on'+type,allList[i].listener); return; } for(var c in allList[i].list[type])if(allList[i].list[type][c].call==call)return; allList[i].list[type].push({ call:call, data:obj.data }); return; } } var objListener={ ele:ele, listener:(function(ele,i){ return function(evt){ handler.call(ele,evt,i); } })(ele,allList.length), list:new Object } objListener.list[type]=[{ call:call, data:data }]; allList.push(objListener); if(ele.addEventListener)ele.addEventListener(type,objListener.listener,false); else if(ele.attachEvent)ele.attachEvent('on'+type,objListener.listener); }, Del:function(ele,type,call){ for(var i in allList){ if(allList[i].ele==ele){ if(type&&call){ for(var s in allList[i].list[type]){ if(allList[i].list[type][s].call==call){ delete allList[i].list[type][s]; return; } } }else if(type){ ele[type]=null; delete allList[i].list[type]; }else{ for(var t in allList[i].list){ if(ele.removeEventListener)ele.removeEventListener(t,allList[i].listener,false); else if(ele.detachEvent)ele.detachEvent('on'+t,allList[i].listener); } delete allList[i]; } return; } } }, Init:function(ele,type){ if(document.createEvent&&ele.dispatchEvent){ var evt=document.createEvent('HTMLEvents'); evt.initEvent(type,true,true); ele.dispatchEvent(evt); }else ele.fireEvent(type,event); } } })(); Метод Add: Event.Add(ele,type,call,data); obj - DOM-узел ele. Значение свойства data будет передано в указанный обработчик вторым аргументом. Обработчики будут вызваны в контексте ele. Метод Del не изменился. Если обработчик возвращает false - это не только вызовет методы остановки просачивания и выполнения дефолтных обработок, но и остановит вызовы следующих обработчиков. Я посчитал, что false - это полный stop для события:) На самом деле передача data в обработчик немного увеличила код и кому-то может показаться лишним, но это иногда бывает действительно необходимо. Классический пример: // Вариант 1 function obj(data){ var _this=this; this.data=data; this.call=function(){ alert(_this.data); } this.ele=document.createElement('div'); this.ele.onclick=this.call; } // Вариант 2 function obj(data){ this.data=data; this.ele=document.createElement('div'); Event.Add({ ele:this.ele, data:this },'click',this.call); } obj.prototype.call=function(evt,obj){ alert(obj.data); } Какой вариант для вас предпочтительнее?! Примерно из-за такой ситуации я и начал писать библиотеку. |
function obj( var1, var2, ... ){ this.var1 = var1; this.var2 = var2; ... this.ele = document.createElement('div'); Event.Add( this.ele, 'click', this.call, var1, var2, ... ); // call Event.Add( this.ele2, 'click', this.call2, dataArray ); // apply } но на самом деле, есть еще варианты. Посмотри, как jQuery находит объекты ($.cache) |
jQuery принимает только 4 параметра...
И потом нужно определять, что передали - 1 массив или +1 данные... Ну может идея с передачей объекта немного замудрена... Я просто не хотел увеличивать количество передаваемых аргументов... Второй вариант (с 4 параметрами) мне кажется предпочтительнее... А что, если я захочу передать именно массив в обработчик (т.е. call)?! Нет, apply тут лишнее, имхо... |
Изменил Add и описание к нему. Прям как jQuery:)
|
apply удобен когда нужно передать данные дальше, т.е. arguments передать нужно в обработчик. Можно пожертвовать возможность передать обработчику массив с одним элементом, тоже являющимся массивом
|
Цитата:
Цитата:
|
function f() { Event.Add( e, 'click', handler, arguments ); } f(1, 'asd', true); |
Ну понятно, как jQuery... Только как мне это прикрутить?! Не соображу...
|
Цитата:
Event.Add( e, 'click', handler, {1, 'asd', true} ); Не буду переделывать... Этот вариант тоже хороший. |
Подниму-ка я ещё разок эту тему;)
Вот... Переделал немного Event: var Event=(function(){ var allList=new Array; var falseCall=function(evt){ evt.stopPropagation(); evt.preventDefault(); return false; } var handler=function(evt,index){ if(!evt.fix){ if(!evt)evt=event; if(!evt.preventDefault)evt.preventDefault=function(){evt.returnValue=false;} if(!evt.stopPropagation)evt.stopPropagation=function(){evt.cancelBubble=true;} if(!evt.target)evt.target=(evt.srcElement.nodeType==1)?evt.srcElement:evt.srcElement.parentNode; if(!evt.relatedTarget&&evt.fromElement)evt.relatedTarget=(evt.fromElement==evt.target)?evt.toElement:evt.fromElement; if(!evt.which&&evt.button)evt.which=(evt.button&1?1:(evt.button&2?3:(evt.button&4?2:0))); if(evt.pageX==null&&evt.clientX!=null){ var html=document.documentElement,body=document.body; evt.pageX=evt.clientX+(html&&html.scrollLeft||body&&body.scrollLeft||0)-(html.clientLeft||0); evt.pageY=evt.clientY+(html&&html.scrollTop||body&&body.scrollTop||0)-(html.clientTop||0); } if(typeof(evt.wheelDelta)!=='undefined')evt.detail=-evt.wheelDelta/40; evt.fix=true; } for(var i in allList[index].list[evt.type]){ if(allList[index]&&allList[index].list[evt.type]&&allList[index].list[evt.type][i].call.call(this,evt,allList[index].list[evt.type][i].data)===false){ evt.stopPropagation(); evt.preventDefault(); break; } } } return{ Add:function(ele,type,call,data){ if(ele.setInterval&&(ele!=window&&!ele.frameElement))ele=window; for(var i in allList){ if(allList[i].ele==ele){ if(!allList[i].list[type]){ allList[i].list[type]=[{ call:call||falseCall, data:data }]; if(ele.addEventListener)ele.addEventListener(type,allList[i].listener,false); else if(ele.attachEvent)ele.attachEvent('on'+type,allList[i].listener); return; } for(var c in allList[i].list[type])if(allList[i].list[type][c].call==call)return; allList[i].list[type].push({ call:call||falseCall, data:data }); return; } } var objListener={ ele:ele, listener:(function(ele,i){ return function(evt){ Event.obj=evt; handler.call(ele,evt,i); delete Event.obj; } })(ele,allList.length), list:new Object } objListener.list[type]=[{ call:call||falseCall, data:data }]; allList.push(objListener); if(ele.addEventListener)ele.addEventListener(type,objListener.listener,false); else if(ele.attachEvent)ele.attachEvent('on'+type,objListener.listener); }, Del:function(ele,type,call){ for(var i in allList){ if(allList[i].ele==ele){ var handlers=allList[i].list[type]; if(call&&handlers){ for(var s in handlers){ if(handlers[s].call==call){ handlers.splice(s,1); if(handlers.length)return; break; } } } if(type){ if(ele.removeEventListener)ele.removeEventListener(type,allList[i].listener,false); else if(ele.detachEvent)ele.detachEvent('on'+type,allList[i].listener); delete allList[i].list[type]; } for(var s in allList[i].list)return; allList.splice(i,1); return; } } }, Init:function(ele,type){ if(document.createEvent&&ele.dispatchEvent){ var evt=document.createEvent('HTMLEvents'); evt.initEvent(type,true,true); ele.dispatchEvent(evt); }else ele.fireEvent(type,event); } } })(); Вобщем, что поменялось: 1. Найден и исправлен серьёзный баг. 2. Теперь запись: Event.Del(ele);не работает. Пока не нашел красивого решения. 3. Немного оптимизировал как объём кода, так и выполнение. 4. Можно передать такие параметры: Event.Add(ele,'click',false);эта запись эквивалентна: Event.Add(ele,'click',function(evt){return false;})По-моему очень удобно, ибо не создаются лишние функции:) 5. Добавил обработку detail для события onmousewheel в IE. |
Часовой пояс GMT +3, время: 16:36. |