Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Идея сайта... Стоит двигацца дальше?! (https://javascript.ru/forum/project/3686-ideya-sajjta-stoit-dvigacca-dalshe.html)

Kolyaj 06.10.2009 15:50

B~Vladi,
я e1f'а процитирую, вдруг не заметил
Цитата:

Сообщение от e1f
а если нет уже ни всплытия, ни другого обработчика?

upd: видимо заметил :) теперь предлагается onerror для каждого обработчика определять?

И зачем имена функций/методов с большой буквы?

B~Vladi 06.10.2009 15:51

Цитата:

Сообщение от e1f
Частично может помочь window.onerror

А если вынести массив errors, как свойство Event?! И обнулять при каждом вызове обработчков?! Так надо чтоли?!

Kolyaj 06.10.2009 15:52

Цитата:

Сообщение от B~Vladi
Давайте ещё предложения!

Не выпендриваться и добавлять обработчики специально для этого придуманными методами: attachEvent/addEventListener.

Kolyaj 06.10.2009 15:53

Цитата:

Сообщение от B~Vladi
А если вынести массив errors, как свойство Event?! И обнулять при каждом вызове обработчков?!

Самый главный вопрос: в какой момент проверять наличие ошибок?

B~Vladi 06.10.2009 15:53

Цитата:

Сообщение от Kolyaj
теперь предлагается onerror для каждого обработчика определять?

Это не обязательно. Определять нужно, когда собираешься обработать ошибку.

B~Vladi 06.10.2009 15:55

Цитата:

Сообщение от Kolyaj
Не выпендриваться и добавлять обработчики специально для этого придуманными методами: attachEvent/addEventListener.

Ну вот:( И чё всё это зря?!:cray:
Цитата:

Сообщение от Kolyaj
в какой момент проверять наличие ошибок?

Ну если вынести его как Event.errors - то можно как и в момент выполнения обработчиков, так и после них... Если возникло новое событие - значит это новый errors... Так ли?!

B~Vladi 06.10.2009 16:20

Цитата:

Сообщение от Kolyaj
И зачем имена функций/методов с большой буквы?

Методы я пишу с большой... Свойства с маленькой... Так удобно:)
Я частенько к концу раб. дня могу тупить, так что не обращайте внимание:)

По поводу того, как узнать, была ли ошибка...
Я так понимаю, можно пойти 2 путями - где-то это всё сохранять (Event.errors, например) и уже самому смотреть, были ли ошибки...
Или можно вызвать событие window.onerror...
Вобщем, скажите хоть как будет правильнее а?!

B~Vladi 06.10.2009 16:37

Вобщем, теперь сохраняю все ошибки в массив Event.errors (свойство библиотеки).
При генерировании нового события, массив обнуляется.
Если передан обработчик onerror и возникает ошибка - он вызывается в контексте события и передаётся ошибка.

Так пойдёт?!

e1f 06.10.2009 16:37

Честно говоря, я весь текущий спич слабо воспринимаю :) Если я пишу такой обработчик, который может упасть -- я заверну его в try/catch сам.
Onerror -- есть баги, выполнение скрипта-то все равно стопается.
Насчет методов -- а почему не "первая буква маленькая, дальше заглавные большие"? JS-style, вроде бы ;)

B~Vladi 06.10.2009 16:43

Ещё убрал строчку присваивания возвращаемого значения в событие...
Если необходимо передать что-либо в следующий обработчик - достаточно присвоить это в объект event.
Цитата:

Сообщение от e1f
Onerror -- есть баги, выполнение скрипта-то все равно стопается.

Ну значит не будем вызывать onerror:)
Цитата:

Сообщение от e1f
а почему не "первая буква маленькая, дальше заглавные большие"? JS-style, вроде бы

Это у свойств... Мне так проще отличить метод от свойства...

x-yuri 06.10.2009 16:45

по поводу исключений: браузер как поступает? Просто пишет ошибку в журнал и выполняет следующий обработчик и всплытие не прекращается, так? (надо проверить). Вот так и сделай, журналом у тебя будет errors, причем он будет только для отладки использоваться. Т.е. чтобы его можно было отключить. p.s. если обработчик не озаботился обработкой ошибок - это его проблемы

Цитата:

Сообщение от Kolyaj
И зачем имена функций/методов с большой буквы?

а, собственно, почему бы и нет?

Цитата:

Сообщение от Kolyaj
Не выпендриваться и добавлять обработчики специально для этого придуманными методами: attachEvent/addEventListener.

не знаю, на данный момент для меня в этой штуке один плюс - fixEvent, т.е. более читабельный код. С другими решаемыми проблемами не сталкивался

p.s. еще посмотри фреймворки на предмет усовершенствований

B~Vladi 06.10.2009 16:49

Цитата:

Сообщение от x-yuri
браузер как поступает? Просто пишет ошибку в журнал и выполняет следующий обработчик и всплытие не прекращается, так? (надо проверить)

По-моему, всё падает... Проверим.
Цитата:

Сообщение от x-yuri
Т.е. чтобы его можно было отключить

Эм... А как это примерно должно выглядеть?! Т.е. он не должен быть доступен извне, а только после установки некого свойства?!
Цитата:

Сообщение от x-yuri
еще посмотри фреймворки на предмет усовершенствований

Это звучит как "еще посмотри jQuery":)
Да, поковырять можно немного...

x-yuri 06.10.2009 16:57

Цитата:

Сообщение от B~Vladi
А как это примерно должно выглядеть?!

например, метод debug, который включает отладку

Цитата:

Сообщение от B~Vladi
Это звучит как "еще посмотри jQuery"

я не только jQuery имел в виду ;)

e1f 06.10.2009 17:03

Ну, учитывая, что кусок с fixEvent взят явно из jQuery... ;)

B~Vladi 06.10.2009 17:07

Цитата:

Сообщение от e1f
кусок с fixEvent взят явно из jQuery

Он распространается бесплатно:D
Хотя я там target пофиксил;)
Цитата:

Сообщение от x-yuri
например, метод debug, который включает отладку

ВО! Тема...
Т.е. без него и try catch ловить не надо?!

e1f 06.10.2009 17:11

B~Vladi,
неа, это метод, который ты сам руками напишешь, и если Event.debug() == true, то мы работаем в режиме дебуг, со всякими вкусными, но бесполезными для пользователя плюхами, типа алерта стека вызовов :)

x-yuri 06.10.2009 17:26

Цитата:

Сообщение от B~Vladi
Т.е. без него и try catch ловить не надо?!

я же написал
Цитата:

Сообщение от x-yuri
если обработчик не озаботился обработкой ошибок - это его проблемы

или ему это не нужно

x-yuri 06.10.2009 17:30

а вообще можно попытаться придумать конкретную ситуацию, когда если ошибка происходит в одном обработчике, то другой обработчик (с ним связанный) не должен выполняться. Мне в голову ничего не приходит :-?

B~Vladi 06.10.2009 17:45

Цитата:

Сообщение от e1f
это метод, который ты сам руками напишешь

Ясен пень... Я хотел уточнить, что он конкретно будет менять...
Цитата:

Сообщение от x-yuri
я же написал

Аха, понял, туплю:)
Цитата:

Сообщение от x-yuri
а вообще можно попытаться придумать конкретную ситуацию, когда если ошибка происходит в одном обработчике, то другой обработчик (с ним связанный) не должен выполняться

Значит надо указывать останавливать следующие облаботчики или нет... Думается мне, что за это должен отвечать обработчик onerror... Если вернул true - продолжаем вызовы...
Если такого обработчика нет - :-?

B~Vladi 06.10.2009 18:02

Добавил, значт, вот ещё что:
Event.Add(obj,'type',{handler:fnc,onerror:(bool||fnc)})

Здесь:
onerror - если передаётся true - ошибка в обработчике не остановит вызов других. Если false - остановит. Если передаётся функция - обработчик ошибки и возвращает false - вызовы остановятся. Если ничего не передано - вызовы будут останавливаться. Так норм?!

Kolyaj 06.10.2009 18:40

Цитата:

Сообщение от x-yuri
а, собственно, почему бы и нет?

Может потому, что code-style в js другой?

B~Vladi,
т.е. предлагается в каждый обработчик каждого события добавлять код обработки ошибок, который по сути будет console.log, т.к. нам нужно только узнать об ошибке?

B~Vladi 06.10.2009 18:50

Цитата:

Сообщение от Kolyaj
Может потому, что code-style в js другой?

Каждый дрочит так как хочет;)

Цитата:

Сообщение от Kolyaj
т.е. предлагается в каждый обработчик каждого события добавлять код обработки ошибок, который по сути будет console.log, т.к. нам нужно только узнать об ошибке?

Не совсем.
Предлагается возможность обработать ошибку события самому, если это нужно.
Если каждую ошибку обрабатывать не надо - можно установить свойство Debug для Event, передав туда код обработки. Этот Debug будет вызван в конце выполнения всех обработчиков. Если во время выполнения даётся указание прервать вызовы - Debug так же будет вызван, если есть ошибки.

Kolyaj 06.10.2009 18:54

Цитата:

Сообщение от B~Vladi
Каждый дрочит так как хочет

В команде-то пока не дрочил, я так понимаю? Все один да один? :)

Цитата:

Сообщение от B~Vladi
Предлагается возможность обработать ошибку на событие самому, если это нужно.

Мне нужно, чтобы браузер сообщил об ошибке, если она возникла, чтобы я ее потом исправил. В твоем варианте браузер мне ничего не сообщить, я сам должен заботиться о мониторинге массива errors.

B~Vladi 06.10.2009 18:57

Цитата:

Сообщение от Kolyaj
В команде-то пока не дрочил, я так понимаю?

В последнее время только этим и занимаюсь;)
Просто я настолько хороший кодер, что на это закрывают глаза:D
Цитата:

Сообщение от Kolyaj
Мне нужно, чтобы браузер сообщил об ошибке, если она возникла, чтобы я ее потом исправил.

Значит надо бросать исключение... Правильно?!
Цитата:

Сообщение от Kolyaj
В твоем варианте браузер мне ничего не сообщить, я сам должен заботиться о мониторинге массива errors.

этот массив существует только для того случая, когда ошибка ожидается...

e1f 06.10.2009 19:04

Kolyaj,
а стоит ли вообще с этим париться? Не скажется ли на производительности, если мы каждый обработчик будем совать try/catch, нужен он там или нет? Может, лучше я сам в обработчике и проверку сделаю, если надо?

Kolyaj 06.10.2009 19:25

Цитата:

Сообщение от B~Vladi
Значит надо бросать исключение... Правильно?!

Не нужно его ловить, чтобы потом не бросать.

Цитата:

Сообщение от e1f
а стоит ли вообще с этим париться?

Конечно не стоит, я уже написал
Цитата:

Сообщение от Kolyaj
Не выпендриваться и добавлять обработчики специально для этого придуманными методами: attachEvent/addEventListener.

Цитата:

Сообщение от e1f
Не скажется ли на производительности, если мы каждый обработчик будем совать try/catch, нужен он там или нет?

Скажется.

Цитата:

Сообщение от e1f
Может, лучше я сам в обработчике и проверку сделаю, если надо?

А откуда ты знаешь, где ошибка возникнет?

e1f 06.10.2009 19:27

Ну, если наш обработчик не использует никаких глобальных переменных, не опирается на приведение типов, все корректно проверяет -- как там может возникнуть ошибка? Заворачивать вызов каждой функции в try/cacth -- имхо не очень выход.

Kolyaj 06.10.2009 19:32

Цитата:

Сообщение от e1f
Ну, если наш обработчик не использует никаких глобальных переменных, не опирается на приведение типов, все корректно проверяет -- как там может возникнуть ошибка?

Действительно, и откуда они берутся, эти ошибки, ума не приложу. Сидишь, бывает, дебажишь и думаешь, и откуда она взялась.

x-yuri 06.10.2009 23:45

Цитата:

Сообщение от B~Vladi
onerror - если передаётся true - ошибка в обработчике не остановит вызов других. Если false - остановит. Если передаётся функция - обработчик ошибки и возвращает false - вызовы остановятся. Если ничего не передано - вызовы будут останавливаться. Так норм?!

я тебе такого не советовал. Я бы тебе Микеланджело процитировал: "Beauty is the purgation of superfluities". Вот ты все добавляешь функциональность и добавляешь, а она тебе нужна? Apache тоже становился все жирнее и жирнее, и вот теперь есть nginx, lighttpd. Фактически тебе эти обработчики ошибок в обработчиках не пригодятся. Тебе просто нужно сообщать об ошибках, если они возникают. Если обработчик рассчитывает на ошибки, он должен их сам перехватывать. Реальных ситуаций с взаимосвязанными обработчиками я не вижу (если ошибка в первом, второй не должен выполниться). Так как ты назначаешь служебный обработчик, значит он должен ловить исключения и отправлять их по-дальше: setTimeout(function () { throw ... }, 0); Только надо добавить информацию о том, где произошло исключение
p.s. я бы из всего функционала реализовал бы только fixEvents. Не приходит в голову конкретных ситуаций, когда мне остальное может пригодиться

B~Vladi 07.10.2009 10:24

Есть некоторые мысли. Да, действительно всё это лишнее. Как родится новый код - отпишусь.

B~Vladi 08.10.2009 10:46

Вобщем, координальных изменений нет...
Оптимизировал, поймал один баг, немного изименился вызов 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);
}


Какой вариант для вас предпочтительнее?!
Примерно из-за такой ситуации я и начал писать библиотеку.

x-yuri 08.10.2009 11:19

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)

B~Vladi 08.10.2009 11:42

jQuery принимает только 4 параметра...
И потом нужно определять, что передали - 1 массив или +1 данные...

Ну может идея с передачей объекта немного замудрена... Я просто не хотел увеличивать количество передаваемых аргументов...

Второй вариант (с 4 параметрами) мне кажется предпочтительнее...
А что, если я захочу передать именно массив в обработчик (т.е. call)?! Нет, apply тут лишнее, имхо...

B~Vladi 08.10.2009 11:52

Изменил Add и описание к нему. Прям как jQuery:)

x-yuri 08.10.2009 11:53

apply удобен когда нужно передать данные дальше, т.е. arguments передать нужно в обработчик. Можно пожертвовать возможность передать обработчику массив с одним элементом, тоже являющимся массивом

B~Vladi 08.10.2009 11:57

Цитата:

Сообщение от x-yuri
apply удобен когда нужно передать данные дальше

Куда дальше?! А так нельзя передать?!
Цитата:

Сообщение от x-yuri
т.е. arguments передать нужно в обработчик

А event куда тогда?!

x-yuri 08.10.2009 12:02

function f() {

    Event.Add( e, 'click', handler, arguments );
}
f(1, 'asd', true);

B~Vladi 08.10.2009 12:29

Ну понятно, как jQuery... Только как мне это прикрутить?! Не соображу...

B~Vladi 08.10.2009 13:01

Цитата:

Сообщение от x-yuri
function f() {
 
    Event.Add( e, 'click', handler, arguments );
}
f(1, 'asd', true);

Тогда уж проще написать так:
Event.Add( e, 'click', handler, {1, 'asd', true} );

Не буду переделывать... Этот вариант тоже хороший.

B~Vladi 21.10.2009 11:28

Подниму-ка я ещё разок эту тему;)

Вот... Переделал немного 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.