Pull to refresh

Comments 27

UFO just landed and posted this here
Пробовал.
Но там все на много проще. К HTMLInputElement цепляется всплывающий список. Это-то сделать, достаточно просто.
Я больше наблюдаю вот за этим wiki.jqueryui.com/w/page/12138056/Selectmenu
этим wiki.jqueryui.com/w/page/12138055/SelectComboboxAutocomplete
и вот этим wiki.jqueryui.com/w/page/12137757/Combobox

Попытка создать combobox где эта проблема представлена наиболее ярко ведутся уже больше года.
Были убиты уже рабочие прототипы интересных задумок, которые, увы, работали только с мышью, т.к. не было возможности адаптировать их под работу с фокусом.
Решил еще раз посмотреть, после вашего комментария. Похоже я перепутал. Я тогда смотрел datepicker, т.к. когда я начал разработку своего плагина autocomplete еще не существовал.

Разработчики jQuery пришли к такому же решению, что и я
// clicks on the menu (or a button to trigger a search) will cause a blur event
self.closing = setTimeout(function() {
self.close( event );
self._change( event );
}, 150 );


Забавно, даже интервал у нас совпал -))
FireFox требует задержку в 150мс что бы успело инициализироваться событие click после blur
Возникло ощущение, что вы говорите о чём-то важном, но я не могу понять, о чём.
Можете поподробнее рассказать, с какой проблемой столкнулись разработчики этого куска кода и как этот кусок кода им помог?
Давайте рассмотрим проблему на примере автокомплита.
Есть поле ввода и есть выпадающий список (HTMLInputElement и HTMLDivElement)
Автокоплит должен закрываться тогда, когда он теряет фокус ввода.
Так же, мы должны позволить пользователю выбрать вариант с помощью мышки, ткнув ею в выпадающем списке.

В итоге получается такая картина, когда человек кликает по выпадающему списку, происходит событие blur и выпадающий список скрывается. А соответственно мы не можем перехватить событие clickи узнать, какой элемент пользователь выбрал.

И это еще самый простой вариант UI-элемента.
агаа, теперь понятно.
я тоже ещё недавно писал контрол свой экспериментальный, где нужно было узнать, с какого элемента и на какой ушёл фокус.
а, как я понял, никто не регламентирует очерёдности вызова этих событий, и единственный способ узнать — вешать focusin на document.
так я и сделал.
и теперь знаю, с какого на какой элемент скачет фокус.
:)
И вот тут во всю проявляется проблема event.stopPropagation()
Так же, проблема «засирания» HTMLDocument'a множественными обработчиками(негативно сказывается на реакции станицы на действие пользователя)
И самое неприятное в вашем случае, это инструкция .blur() которая не будет генерить события focusin на HTMLDocument
я отлавливаю mousedown, выключаю обработчик blur и через миллисекунду включаю.
Ошибок 132… Вы же их не чистите? :)
Как только мне откроют доступ к исходникам Gmail, обязательно ими займусь :)
Не вижу особых проблем. Можно оверлею (вашему выпадающему меню или календарику) назначить tabIndex = 0 и он будет получать фокус от кликов по нему. После чего ставим 2 листенера на window — на focusin и focusout, и скрывем оверлей, если фокус покидает пределы исходного инпута или оверлея.

Минусы: надо тестировать во всех браузерах, надо немного возиться с таймаутами, и немного извращаться: например, Опера любит дополнительно вызывать focusin на document при фокусировке в инпуте, для этого надо просто приписать костыль, также минусом является то, что оверлей тоже получает фокус и приходится нажимать Tab в 2 раза чаще. чтобы пройтись по всем полям.

Плюсы: все корректно скрывается, можно кликать по оврелею, можно размещать в оверлее элементы управления, и по ним шагать фокусом с клавиатуры.

Правда, при этой схеме, подвох все же есть: оверлей приходится вставлять в дерево сразу после input, и это несет много скрытых багов: например, элементы управления в оверлее становятся частью формы, которой принадлежит input, что очень-очень плохо. Может нарушаться вложенность тегов (если в оверлее есть тег p и мы его, оверлей, вставляем внутрь существующего тега p, IE начинает лихорадить). Если же добавлять оверлей в дети к body, нарушается последовательность перехода табом… (((

А, еще, по моему, глупо брать jQuery UI за основу системы виджетов. jQuery UI — это не система виджетов, а сборник плохого, тормозящего, некачественного кода, который позволяет навесить на кнопку пару лишних свойств, и оно того по моему не стоит. Достаточно посмотреть исходный код, чтобы пропало желание им пользоваться. Также, в нем нет поддержки системы попапов, оверлеев и меню, чтобы корректно отслеживать перемещение фокуса по ним, закрывать и открывать, когда это требуется и т. д.

Вот еще кстати интересная задача при разработке UI: при открытии на странице всплывающего окна, надо как-то удерживать фокус внутри него (чтобы табом нельзя было уйти на страницу под ним).
После чего ставим 2 листенера на window — на focusin и focusout, и скрывем оверлей, если фокус покидает пределы исходного инпута или оверлея.

В этом главная загвоздка. В начале топика я пишу, что именно это не верное решение.

На счет jQuery UI — соглашусь. Только вот он очень популярный, а виджет я делаю как для себя, так и для людей.
У вас очень плохим языком статья написана, трудно понять в чем именно проблема, но:

> Проблема номер два — генерация событий blur и focusout в родительском элементе, когда происходит click на дочернем HTMLInputElement(атрибут tabindex влияет лишь на получение фокуса с помощью Taba). Что в свою очередь «ломает» нам всю логику работы с разрабатываемым UI-элементом.

Я в упор не вижу, в чем проблема. Вы хотите, чтобы по клику на инпут внутри виджета виджет генерировал события focusin? Не понимаю, нафига это нужно. Вы хотите игнорировать смену фокуса в пределах виджета? В любом случае, всегда можно отслеживать смену фокуса листенером на window или на верхнем элементе виджета.
Да, хочу игнорировать смену фокуса внутри элемента.
Его отслеживание на window — это плохое решение т.к. event.stopPropagation() ломает работу виджета.
+ отрицательно сказывается сказывается на отзывчивость страницы. Каждое изменение фокуса, будет проверяться X раз, где X — количество виджетов, которые работают подобным образом
Неверно (по моему мнению). Во-первых, если кто-то для события focusout вызывает event.stopProragation(), он сам себе злобный буратино. Так можно любую систему разломать.

Во-вторых, имхо, предположение про замедление работы браузера — бред. Смотрите, сколько событий смены фокуса может нагенерировать пользователь? Если он зажмет и не будет отпускать клавишу Tab, будет генерироваться около 5 событий blur, focus, focusin и focusout в секунду. Если у нас есть 1 обработчик, наверху страницы, то вызываться он будет только один раз. 20 вызовов простой функции в секунду (если вы не пишете там ничего сложного) не замедлят работу браузера.

И смешно говорить про замедление, когда вы используете тяжелый jQuery и криво написанный jQuery UI. Там в одних конструкторах столько кода поналяпано, что у вас тормозить страница будет и без ваших стараний.
Есть две составляющие:
— доступность расширения
— комплексность

В первом случае, мне приходится считаться с простотой его подключения и массовость. Исходя из этого выбор пал на jQuery.

Во втором случае, я должен обеспечить безглючность плагина, автономность и не влияние его на окружение. При навешивании событий на window, HTMLDocument (и т.п.) я фактически, оставляю дыры для утечек памяти и возникновения ошибок. Т.к. DOM плагина могут удалить. К тому же, delegate (навешивание события на родительскую ноду, для отслеживания события на дочерней) зарекомендовал себя, как очень «тяжелый» метод. Не раз сталкивался, что отказ от него позволял изменить впечатление о сайте с «тормознутого» до «быстрого»
Наверно, в вашем случае применение jQuery UI более чем оправдано.

Но про обработку событий на window, мне кажется, вы ошибаетесь. Навешивание на корень документа опасно, если это событие из разряда mouseover/mouseenter/mouseout/mousemove/scroll. А как перехват кликов может тормозить браузер, если юзер в это время никуда не кликает?

Насчет удаления DOM — проблем нет, при удалении элементов от них перестанут поступать события. А вот навешивая обработчики на сам виджет (а не на корень), вы наоборот усугубляете проблему, так как:

1) мы должны в начале загрузки каждой странице (в этот момент парсятся скрипты, достраивается ДОМ, CSS, процессор сильно нагружен и лучше его не беспокоить в этот момент) на сайте вызывать медленный метод $('.someClass').plugin(), который медленно ищет на полузагрузившейся странице нужные классы и медленно-медленно цепляет к ним обработчики.

Фаерфокс, например, создает индекс для поиска по классам при первом вызове getElementsByClassName, и первый вызов этой ф-и будет медленным. Лучше ее вообще не вызывать. IE ниже 8 версии вообще не может найти элемент по имени класса.

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

Я могу ошибаться, но интуиция мне подсказывает, что навешивание 1 обработчика быстрее беготни по дереву, сложного поиска селекторов и навешивания множества обработчиков.
1) На самом деле в HTMLDocument нужно помещать уже «собранный» виджет. Где все события уже подцеплены и делать это надо после того, как подгрузится весь основной DOM.
$( function () {
var el = $( '...' ).bind('click', function() { ... };
$(document).append(el);
});

Так что тут все просто отлично

2) Вставку контента нужно оборачивать в объект(функцию) который будет знать, что подгружать и какие виджиты подключать, так что тут проблем не вижу.
Оверхед при использовании delegate по сравнению с навешенным событием будет минимум в 10 раз(правда на 1000 итераций 8мс или 80мс не так уж и важно, но я использовал простейший счетчик внутри, и скорее всего у многих браузеров сработала оптимизация, т.к. повышение количество итераций почти не сказалось на времени выполнения. IE вешался при навешивании delegate 10000 раз :) )
При этом, delegate при каждом вызове функции в родителе будет проверять event.currentTarget на совпадение с правилом — что не есть очень хорошо.
Повторюсь, в нескольких проектах уход от delegate творило чудеса в восприятии людьми реагирование страниц на работу с пользовательским вводом.
Вот еще кстати интересная задача при разработке UI: при открытии на странице всплывающего окна, надо как-то удерживать фокус внутри него (чтобы табом нельзя было уйти на страницу под ним).
мне кажется, что тут необходимо смотреть в сторону iframe, хотя нужно проверять
Я правильно понял, что проблема в том чтобы для выпадающего списка(например), при клике на элемент списка, контрол не терял бы фокус и не отрабатывал событие onblur, но при общей потере фокуса контролом, отрабатывал бы его корректно?
Мне кажется, что можно как-то извратиться с элементами label, object и всеми другими элементами, которые могут содержать другие элементы и поддерживают эти события, они же отрабатывает focus, blur и т.п. А вообще я бы попробовал поковыряться в DTD и создать свой элемент control, который объединялбы свойства div и button(последняя не передает события click внутренним элементам)
* сорри за кашу, перечитал DTD
P.S. Видимо, браузерам совершенно по барабану DTD когда разговор доходит до поведения элементов. Может что-то не так сделал. Но, как говорится, не взлетел (
На сколько я знаю, считывают DTD браузеры только в случае с Xml. С html поступают проще, ищут в по стандартным, если не находят, то переключаются в Quirks mode.
Sign up to leave a comment.

Articles