LINUX.ORG.RU

[javascript] Как временно запретить событие onclick дочернего элемента?

 


0

0

Я хочу сделать на форме контекстную помощь. Для этого в html добавляю

<div class='helper'><a href='#'  id='helper'>Контекстная помощь</a></div>
а скриптом при загрузке страницы делаю:
$('helper').onclick = startHelp;
Соответственно, функции:
function startHelp(evt){
        evt.stopPropagation();
        evt.preventDefault();
        document.body.style.cursor = "help";
        setTimeout(function(){document.body.onclick = Help;}, 30);
}

function Help(evt){
        evt.stopPropagation();
        evt.preventDefault();
        document.body.onclick = '';
        document.body.style.cursor = "default";
        showHelp(evt.target.id);
}
Но вот в чем беда: stopPropagation() почему-то не работает (firefox 3.5.5). startHelp сразу вызывает функцию Help, но это я решил введением таймаута. А вот в Help помимо самой функции showHelp еще и вызывается обработчик onclick того элемента, по которому я щелкнул.

Как можно решить эту проблему? Может быть, я что-то делаю не так? Или придется делать обработчик onmouseover/onmouseout, который будет при наведении мыши на элемент отменять его onclick, а при отводе - восстанавливать?

☆☆☆☆☆

Я так понял, что сначала вызывается onclick самого нижнего в иерархии объекта, а затем уже проверяются объекты выше. А вот как временно все onclick'и позапрещать, кроме document.body?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от trashymichael

Проверил - не помогает. Это же элемент более высокого уровня иерархии, чем конечные div'ы, на которые вешаются onclick...

Eddy_Em ☆☆☆☆☆
() автор топика

Сделал вот такой костыль:

// Контекстная справка
function startHelp(evt){
	evt.stopPropagation();
	evt.preventDefault();
	document.body.style.cursor = "help";
	document.body.onclick = Help;
	document.body.onmouseover = stoponclick;
}

function Help(evt){
	evt.stopPropagation();
	evt.preventDefault();
	document.body.onclick = '';
	document.body.style.cursor = "default";
	document.body.onmouseover = '';
	alert('id='+evt.target.id+' name='+evt.target.name);
}

var oldclc, oldmout;
function stoponclick(evt){
	var obj = evt.target;
	if(obj == document.body) return;
	oldclc = obj.onclick;
	oldmout = obj.onmouseout;
	obj.onclick = Help;
	obj.onmouseout = releaseonclick;
	obj.style.cursor = "help";
}
function releaseonclick(evt){
	var obj = evt.target;
	obj.onmouseout = oldmout;
	obj.onclick = oldclc;
	obj.style.cursor = "default";
}
Работает, но checkbox'ы и radio отмечаются (правда, после отработки функции возвращаются в старое положение). Мелочь, но некрасиво.

Да и кажется мне, возможно более элегантное решение. Но я в JavaScrit ноль.

Eddy_Em ☆☆☆☆☆
() автор топика

Я бы сохранял все функции, установленные на onclick, вместе со ссылками на DOM-объект в специальном массиве, а onclick'и чистил. Потом, при необходимости, возвращал обратно.

Zhid
()
Ответ на: комментарий от Zhid

Я так и делаю, но только для объекта, поверх которого находится указатель. Сейчас код выглядит так:

var tipobj;

function startHelp(evt){
	evt.stopPropagation();
	evt.preventDefault();
	document.body.style.cursor = "help";
	document.body.onclick = Help;
	document.body.onmouseover = stoponclick;
}

function Help(evt){
	evt.stopPropagation();
	evt.preventDefault();
	document.body.onclick = '';
	document.body.style.cursor = "default";
	document.body.onmouseover = '';
	helptip(evt);
}

var oldclc, oldmout;
function stoponclick(evt){
	var obj = evt.target;
	if(obj == document.body) return;
	oldclc = obj.onclick;
	oldmout = obj.onmouseout;
	obj.onclick = Help;
	obj.onmouseout = releaseonclick;
	obj.style.cursor = "help";
}
function releaseonclick(evt){
	var obj = evt.target;
	obj.onmouseout = oldmout;
	obj.onclick = oldclc;
	obj.style.cursor = "default";
}
function helptip(evt){
	tipobj = document.createElement("DIV");
	tipobj.id = 'helptip';
	tipobj.onclick = rmtip;
	tipobj.className = "tooltip";
	document.body.appendChild(tipobj);
	tipobj.innerHTML = helpgen(evt);
	releaseonclick(evt);
	positiontip(evt);
}

function helpgen(evt){
	var objid = evt.target.id, objname = evt.target.name;
	return ("id="+objid+" name="+objname);
}

function positiontip(e){
	var wd = tipobj.offsetWidth, ht = tipobj.offsetHeight;
	var curX = e.clientX + 25;
	var curY = e.clientY - ht/2;
	var btmedge = document.body.clientHeight - curY - 15;
	var rightedge = document.body.clientWidth - curX - 15;
	if(rightedge < wd) curX -= wd+50;
	if(btmedge < ht) curY -= ht-btmedge+15;
	if(curY < 15) curY = 15;
	tipobj.style.left = curX+"px";
	tipobj.style.top = curY+"px";
}

function rmtip(evt){
	document.body.removeChild(evt.target);
}
Остается придумать, как «подчищать» старые «хелпы» при повторной активации режима справки, т.к. вот так не работает:
function helptip(evt){
	var tmp = document.getElementById('helptip');
	if(typeof(tmp) != "undefined"){
		document.body.removeChild(tmp);
		alert(typeof(tmp));
	}
	else alert('do');
	tipobj = document.createElement("DIV");
	tipobj.id = 'helptip';
	tipobj.onclick = rmtip;
	tipobj.className = "tooltip";
	document.body.appendChild(tipobj);
	tipobj.innerHTML = helpgen(evt);
	releaseonclick(evt);
	positiontip(evt);
}
ни старая «подсказка» не удаляется, ни алерты (ни один) не выскакивают. Причем, в консоли ошибок пусто.

Eddy_Em ☆☆☆☆☆
() автор топика

Не хочется текст для каждого checkbox'а и пр. помещать в отдельный div. Пробую так:

function helpgen(evt){
	var obj = evt.target;
	var objid, objname, ss="";
	do{
		objid = obj.id; objname = obj.name;
		ss += "id="+objid+" name="+objname+"; parentid="+obj.parentNode.id+"<br>";
		while((obj = obj.previousSibling) && obj.nodeType != 1);
		if(!obj) break;
	}while(objid == "" && objname == null);
	return (ss);
}
но не работает! В инспекторе DOM firefox'а для текста, стоящего после соответствующего checkbox'а пишется правильный previousSibling - этот самый checkbox, а вот когда я щелкаю по нему мышью, судя по появляющемуся тексту, previousSibling вообще прародительский элемент. Ничего не понимаю...

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Как обычно, т.к. языками не владею, пошел в лоб: в html-коде каждый элемент, на который нужна подсказка тупо заключил в отдельный <div> или <span> с собственным id-ом (или именем, если нужно выводить один и тот же текст подсказки для нескольких объектов).

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Да, если кого заинтересует, текст всех функций могу выложить на pastebin.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> html-коде каждый элемент, на который нужна подсказка тупо заключил в отдельный <div> или <span> с собственным id-ом (или именем, если нужно выводить один и тот же текст подсказки для нескольких объектов).

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

SV0L0CH
()
Ответ на: комментарий от SV0L0CH

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

Во-первых, люблю велосипедостроение (так лучше ЯП изучать), во-вторых, зачем мне мегабайты кода, который не будет использоваться?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

ага. гигабайты. поверь, чувак, с 15кб запакованного jquery твои велосипеды были бы покороче раза в три. ты бы попробовал, это действительно круто, кроме того решает разные кроссбраузерные фенечки ит.п.

trashymichael ★★★
()
Ответ на: комментарий от SV0L0CH

оно некорректно работает с xhtml/svg

Если так, то этот хваленый jquery вообще не нужен.

trashymichael

кроме того решает разные кроссбраузерные фенечки

Оно мне не нужно: мои скрипты в geko-based браузерах работают, в konqueror и опере работают. А нераспространенные браузеры я поддерживать не собираюсь. Если браузеры на основе webkit наберут популярность, буду и в них проверять.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Велосипеды занимают в несколько раз больше места, чем jQuery + строчка кода вместо каждого велосипеда.
Еще и понятнее.

Zhid
()
Ответ на: комментарий от drakmail

кстати, ЛОР тоже использует jqeury(правда старую версию)

SV0L0CH
()
Ответ на: комментарий от drakmail

пруф Гугл просто использует jQuery в некоторых своих проектах.

Ладно, все равно мне это не нужно.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от trashymichael

>с 15кб запакованного jquery твои велосипеды были бы покороче раза в три

Т.е. браузеры уже научились пакованные скрипты исполнять или таки ему придётся распаковать всю эту 100килобайтную лапшу и выполнить?

Deleted
()
Ответ на: комментарий от Deleted

>Т.е. браузеры уже научились пакованные скрипты исполнять или таки ему придётся распаковать всю эту 100килобайтную лапшу

Вообще-то, от распаковки 100 килобайт ваш компьютер не пострадает. Если загружать их каждый раз при переходе на новую страницу - еще туда-сюда, если модем. Это раз.

Во-вторых, вы таки удивитесь, но браузер исполняет именно пакованную jQuery, потому что единственные следы «паковки» там заключаются в убирании лишних символов.

и выполнить


jQuery - это библиотека. Библиотеки не выполняются.

Zhid
()
Ответ на: комментарий от Zhid

>от распаковки

Срочно перечитай.

но браузер исполняет именно пакованную jQuery, потому что единственные следы «паковки» там заключаются в убирании лишних символов.


ORLY?

About 24KB in size (Minified and Gzipped)

Gzipped


Gzipped


Gzipped



jQuery - это библиотека. Библиотеки не выполняются.

Javascript



trollface.jpg

Deleted
()
Ответ на: комментарий от Deleted

>155KB, Uncompressed Code

Оно ещё и пухнет :}

Deleted
()
Ответ на: комментарий от Deleted

gzip'ом сжимается весь HTTP-траффик (если это поддерживается и клиентом и сервером), а не только jQuery.

anonymous
()
Ответ на: комментарий от Zhid

> jQuery - это библиотека. Библиотеки не выполняются.

То что в javascript принято называть библиотеками, не соответствует бинарными библиотекам: во время загрузки браузер уже парсит javascript-код.

anonymous
()
Ответ на: комментарий от anonymous

Воспользуйся сложным инструментом «браузер» и открой штук 20 вкладок с этим добром одновременно, возможно с плагинами. Радуйся.

Deleted
()
Ответ на: комментарий от Deleted

>Воспользуйся сложным инструментом «браузер» и открой штук 20 вкладок с этим добром одновременно, возможно с плагинами. Радуйся.

Я понимаю, что в файерфоксе 20 вкладок - это ужос и ад, а нормальные браузеры спокойно все пережуют. Не говоря уж о том, что у пользователя в принципе не может возникнуть ситуации, когда он откроет 20 вкладок одновременно, и на всех начнет загружаться jQuery.

И при чем тут плагины?

Zhid
()
Ответ на: комментарий от Zhid

>Я понимаю, что в файерфоксе 20 вкладок - это ужос и ад, а нормальные браузеры спокойно все пережуют

Т.е. нагрузка есть. Зачем её увеличивать? Я об этом.

Не говоря уж о том, что у пользователя в принципе не может возникнуть ситуации, когда он откроет 20 вкладок одновременно, и на всех начнет загружаться jQuery.


Вот не надо. Всякое случается, особенно с популярным ныне использованием JS-«библиотек» (коих больше одной).

Под плагинами подразумевались плагины jQuery.

Deleted
()
Ответ на: комментарий от Deleted

> Воспользуйся сложным инструментом «браузер» и открой штук 20 вкладок

Мой умный друг, тебя попросили привести цифры, характеризующие время парсинга javascript-кода. А ты нам рассказываешь как долго у тебя открываются 20 вкладок.

anonymous
()
Ответ на: комментарий от anonymous

Уговорил, скрипты выполняются в астрале, за время равное нулю и не требуют памяти для выполнения. Следующий.

Deleted
()
Ответ на: комментарий от Deleted

Мой друг, ты сдулся быстрее воздушного шарика! Очень жаль, но теперь ты не «умный друг», а просто «друг».

anonymous
()
Ответ на: комментарий от Deleted

>Т.е. нагрузка есть. Зачем её увеличивать? Я об этом.

Чтобы все работало хорошо.

Вот не надо. Всякое случается, особенно с популярным ныне использованием JS-«библиотек» (коих больше одной).

Я вам гарантирую, что ни один пользователь на планете Земля не откроет одновременно 20 вкладок с jQuery, а если это кто-то сделает, чтобы продемонстрировать, как у него все тормозит, то ССЗБ.

А за использование больше одной JS-библиотеки, конечно надо убивать. И то, даже сайты, снабженные prototype, aculous, mootols и jQuery одновременно, относительно свободно ворочаются и, опять же, браузер от них умирать не хочет.

Под плагинами подразумевались плагины jQuery.

Вот я и спрашиваю, при чем тут плагины (jQuery).

Zhid
()
Ответ на: комментарий от Zhid

Вот же достали со своими jQuery. Да мне эта библиотека 100 лет не нужна. Зачем подгружать кучу лишнего кода? Мои велосипеды весят намного меньше.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Zhid

>ни один пользователь на планете Земля не откроет одновременно 20 вкладок с jQuery

Ты никогда не открывал больше 1 страницы на сайте за раз что ли? Ну может не 20, но штук у меня 10 бывает довольно часто.

Вот я и спрашиваю, при чем тут плагины (jQuery).


Они тут при том, что ещё увеличивают размер кода.

Deleted
()
Ответ на: комментарий от Deleted

>Ты никогда не открывал больше 1 страницы на сайте за раз что ли? Ну может не 20, но штук у меня 10 бывает довольно часто.

Открывал, но не одновременно же.

Скрипт - это не flash-баннер с кодом while (true) nextFrame();

Ну ладно, загрузился он один раз при первом заходе на сайт, разгзиповался, распарсился. Дальше что? Каким образом он влияет на производительность?

Они тут при том, что ещё увеличивают размер кода.

Обычный плагин jQuery - это десяток строк кода на jQuery. Велосипеды на-а-амного длиннее.

Zhid
()
Ответ на: комментарий от Eddy_Em

>Вот же достали со своими jQuery.

Складывается впечатление, что за вами кто-то ходит целыми днями и скандирует jQuery, jQuery. Нравится плача есть кактус - ну ешьте.

Зачем подгружать кучу лишнего кода?

1. Ускорение сроков разработки. 2. Упрощение работы с DOM. 3. Упрощение создания каких-либо спецэффектов. 4. Обеспечение совместимости скриптов со всеми браузерами, включая IE6.

Достаточно?

Мои велосипеды весят намного меньше.

Вы уже продемонстрировали, сколько весят ваши велосипеды.

Zhid
()
Ответ на: комментарий от Zhid

>Открывал, но не одновременно же.

Почему нет? Жмакаешь кучу ссылок по теме, потом уже смотришь, заодно они и грузятся пока ты, быть может, читаешь одну из них.

Ну ладно, загрузился он один раз при первом заходе на сайт, разгзиповался, распарсился. Дальше что? Каким образом он влияет на производительность?


Жрёт память, события обрабатывает (если есть).

Обычный плагин jQuery - это десяток строк кода на jQuery. Велосипеды на-а-амного длиннее.


У топикстартера тогда не велосипед, а всего лишь палка-копалка. Либо ты просто на JS не писал никогда :}

Deleted
()
Ответ на: комментарий от Zhid

>Складывается впечатление, что за вами кто-то ходит целыми днями и скандирует jQuery, jQuery

Здесь это делают постоянно.

Нравится плача есть кактус - ну ешьте.


trollface.svgz

1. Ускорение сроков разработки.

2. Упрощение работы с DOM.



Что ты там в палке-копалке ускорить и упростить собрался?

3. Упрощение создания каких-либо спецэффектов.


Расстреливать этих. К счастью, скоро будет CSS анимация и это применение наконец сдохнет.

4. Обеспечение совместимости скриптов со всеми браузерами, включая IE6.


Это есть и так, особенно если делаешь что-то маленькое.

Deleted
()
Ответ на: комментарий от Deleted

>Здесь это делают постоянно.

У вас паранойя.

Что ты там в палке-копалке ускорить и упростить собрался?

Время разработки. 15 минут вместо 5 часов.

Расстреливать этих. К счастью, скоро будет CSS анимация и это применение наконец сдохнет.

Ну так «спецэффекты» - это немного больше, чем «CSS анимация».

Это есть и так, особенно если делаешь что-то маленькое.

CSS-анимация - нет. AJAX - нет. Работа с атрибутами элементов - нет. Поиск элементов в DOM - нет.

Zhid
()
Ответ на: комментарий от Zhid

>У вас паранойя.

Просто часто заглядываю.

Время разработки. 15 минут вместо 5 часов.


Выбросьте ваших индусокодеров уже.

Ну так «спецэффекты» - это немного больше, чем «CSS анимация».


Например?

AJAX - нет.


ORLY? Оно работает и так, враппер там совсем небольшой.

Работа с атрибутами элементов - нет


Шо? Работало всю жисть.

Поиск элементов в DOM - нет.


Именно что да. Хотя зависит от запросов. Если нужны селекторы, то в IE6, конечно, таких нет.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.