Ext.FocusManager
Куда подевался Ext.FocusManager?
Как теперь понять, на чем фокус стоит? Как отслеживать перемещение фокуса? |
Ext.FocusManager убит, расчленён, проткнут осиновым колом в его чёрное сердце, выжжен напалмом, пепел захоронен под Чернобыльским саркофагом, и имя его забыто. Я это сделал собственноручно и с превеликим удовольствием, поэтому как доктор говорю.
Как понять, на чём фокус стоит: // всегда было var focusedElement = document.activeElement; // Вернёт то же самое, если вам так удобнее focusedElement = Ext.Element.getActiveElement(); // Вернёт компонент, которому принадлежит сфокусированный элемент // Легко может оказаться null var focusedComponent = Ext.ComponentManager.getActiveComponent(); Как отслеживать перемещение фокуса... Вот это вопрос на миллион долларов, с радиоактивными тентаклями которого я бодаюсь уже четвёртый год. В тривиальном случае: component.on('focusenter', function() { console.log('компонент сфокусирован'); }); component.on('focusleave', function() { console.log('компонент потерял фокус'); }); Очень надеюсь, что менее тривиальные случаи вас не побеспокоят. ;) |
focusenter мне не поможет отследить фокус.
Потому что component не известен. И собственно отслеживание фокуса нужно как раз для того, чтобы узнать component, на котором фокус. Вот это Ext.ComponentManager.getActiveComponent(); конечно уже лучше. Но как отследить изменение фокуса? Хотя можно по идее делать по цепочке. 1) узнать текущий фокус Ext.ComponentManager.getActiveComponent(); 2) подписаться на focusleave 3) как только происходит focusleave тут же перейти в пункт 1. Муторный способ однако... |
Объясните подробнее, чего хотите добиться.
|
Хочу отслеживать фокус. Например, при смене фокуса, чтобы в консоли появлялось сообщение: фокус изменен с компонента1 на компонент2
|
Отслеживание фокуса само по себе особого смысла не имеет, только если из праздного любопытства. Скорее всего вам это нужно для каких-то конкретных целей, например валидирования данных в форме или ещё чего-нибудь. Вот это я и пытаюсь выяснить: какова ваша задача, в чём цель отслеживания фокуса?
Это я не педантизма ради, просто accessibility в целом и управление фокусом в частности это как раз одно из моих основных направлений работы в Sencha. Я могу вам подсказать, как сделать то или это, но мне нужно понимать, чего вы хотите добиться, чтобы посоветовать оптимальный вариант. |
Вы наверное все секреты можете выведать. Да, мне нужно прикрутить чертов сканер штрих-кодов к браузеру. Таблицы grid к сожалению не пропускают пробелы и Enter-ы. Вот сижу и думаю как бы эту неприятность обойти.
|
Мне ваши секреты ни к чему, правда. :) Но я рад, что мы постепенно продвигаемся к цели.
Grid не "не пропускает" пробелы и Enter, эти клавиши имеют специальное значение. Пробел выделяет строку или ячейку, Enter переводит таблицу из навигационного режима (Navigable mode) в активизационный режим (Actionable mode). Названия и поведение таблицы взяты прямиком отсюда: https://www.w3.org/TR/wai-aria-practices/#grid. Изменять это поведение в общем случае я бы не рекомендовал, но если есть чёткое понимание, как UI должен работать, то можно сделать исключение. Хотя и непонятно пока, зачем. Вам нужно со сканера данные получать и вставлять в таблицу? В этом случае можно не обращать внимание на фокус и просто добавлять записи в Store. Grid знает, что нужно делать, когда в нём сфокусирована ячейка и надо обновить таблицу. Или задача в чём-то ещё? |
Сканер отправляет строку с префиксом и постфиксом. В качестве постфикса используется код 13 Enter. И если случайно (пользователь все может) фокус будет на каком-либо гриде, то 13-й код не пройдет и штрих-код не будет считан (точнее его конец не будет считан).
У меня работа со сканером глобальная. То есть не привязана ни к какому элементу. Поэтому пользователю не требуется перед сканированием указывать фокус (то есть специально выбирать элемент, куда будет произведен ввод со сканера). |
А какой префикс? И вообще, какие символы приходят со сканера и сколько?
|
$<цифры-буквы><13>
С баксом проблем нет, грид его пропускает. И все остальное тоже, кроме 13. . |
Цитата:
Цитата:
Пробовал найти такую опцию в классах: Ext.view.AbstractView Ext.view.View Ext.panel.Table Ext.grid.Panel . |
Цитата:
Хм. Если подумать, то задачка-то забавно нетривиальная даже без учёта вопроса с браузерным окном. Отслеживание активного компонента тут слабо поможет, особенно если вашему приложению нужно работать в IE. Я бы пошёл другим путём: можно установить обработчик события keydown на уровне документа со срабатыванием в фазе перехвата, и при опознавании префикса "подставлять" под следующие за ним "нажатия клавиш" некое специальное поле. Примерно так: Ext.define('My.app.Application', { extend: 'Ext.app.Application', launch: function() { this.scannerField = new Ext.form.field.Text({ renderTo: Ext.getBody(), floating: true, hidden: true, focusOnToFront: true, cls: 'x-hidden-clip', shadow: false, listeners: { specialkey: function(field, e) { if (e.getKey() === e.ENTER) { e.preventDefault(); e.stopEvent(); // Это просто чтобы не заморачиваться с разрешением // scope через references в этом примере Ext.app.Application.instance.fireEvent('scanner_input', this.getValue()); this.setRawValue(''); this.hide(); } } } }); Ext.getDoc().on('keydown', function(e) { // 52 это код клавиши для '$' if (e.getKey() === 52) { e.preventDefault(); e.stopEvent(); Ext.app.Application.instance.scannerField.show(); return false; } }, { capture: true }); } }); Это решение не на 100% свободно от побочных эффектов, но в вашем случае такого решения скорее всего вообще нет. Для пущего спокойствия душевного, я бы проделал серию бесчеловечных экспериментов над живым сканером; главный вопрос это насколько быстро случается "ввод", т.е. каков разрыв по времени между префиксом и постфиксом. Я очень сильно подозреваю, что разрыв близок к 0 мс, но могут быть варианты. Если разрыв минимален, то вышеописанное решение должно иметь приемлемую надёжность. Я протестировал по-быстрому в Chrome, но по идее в IE тоже должно сработать. Учтите также, что несмотря на кажущуюся простоту кода, механизмы здесь задействуются сложные и колдунство вельми сильное. Если нужно что-нибудь поменять, лучше сперва спросите. Я с удовольствием объясню, что и как, но это может оказаться надолго. :) |
Цитата:
Цитата:
Здесь я ничего не нашел: http://docs.sencha.com/extjs/6.0/6.0...iner-method-on Цитата:
2) И еще вопрос: А зачем после $ надо показывать поле Ext.app.Application.instance.scannerField.show(); а потом после 13 - скрывать? Из-за этой опции focusOnToFront: true? Хитро однако... . |
Цитата:
Цитата:
Цитата:
Цитата:
Поэтому поле сделано невидимым, но фокусируемым, с помощью CSS правила clip: rect(0,0,0,0), которое применяется стилем 'x-hidden-clip'. Остальные хитрости как раз для автомагического управления фокусом: поле у нас "плавающий" компонент с абсолютным позиционированием в теле документа, поэтому в раскладках не участвует и на другие компоненты не влияет. Когда мы это поле показываем через scannerField.show(), глобальный ZIndexManager сортирует свою коллекцию плавучих компонентов и выпихивает наверх наше поле, попутно его фокусируя. Поле, оказываясь наверху стека и получая фокус, запоминает предыдущий сфокусированный элемент и отпуливает фокус обратно, когда мы это поле скрываем. Флаг focusOnToFront должен быть true по умолчанию для всех плавучек, но я просто подстраховался, т.к. некоторые классы его меняют и я не помню точно, какие именно. Примерно так, если без нюансов. :) А ещё если подумать, то надо очистку поля через setRawValue('') передвинуть из обработчика specialkey в глобальный перехватчик. И вопрос о длительности интервала между $ и Enter был вовсе не праздным, промышленную версию этого решения неплохо бы обвешать предохранителями на тему ложных срабатываний. Как говорил незабвенный поручик, случаи разные бывают... |
Цитата:
Это для задач, где пользователь не решает, какой браузер ему использовать. Цитата:
Я попробовал в действии опцию { capture: true }. Для keydown она работает, грид не может перехватить и заблокировать событие, а вот для keypress эта опция не сработала, грид заблокировал событие, почему такая разница??? В итоге, мне в общем-то достаточно опции capture, чтобы решить проблему, разве что событие keypress придется поменять на keydown. Но, единственный недостаток решения это то, что capture это недокументированная опция, надо заметить... . |
Здесь тоже есть опция capture, но недокументированная
http://docs.sencha.com/extjs/6.0/6.0...xt.util.KeyMap http://docs.sencha.com/extjs/6.0/6.0...xt.util.KeyNav плюс еще опция priority тоже есть. |
Цитата:
Цитата:
Цитата:
Цитата:
|
Цитата:
Но ведь опция { capture: true } гарантированно решает эту проблему. Зачем "максимально использовать возможности браузера", если проблема перехвата так легко решается? Хотя бы ценой смены события keypress на keydown. |
Цитата:
А самое главное: для обработки этих событий вам нужно писать код, а код === баги === стоимость поддержки. Единственный способ уменьшить количество багов, это уменьшить количество кода. Но вы не подумайте чего, я не буду вас уговаривать. Ваш проект, ваша головная боль... ;) |
Цитата:
|
Цитата:
|
Первая версия универсального контроллера ввода штрих-кодов. Для его использования по идее надо сделать контроллер обработки, который подписывается на событие barcode.
/* global Ext */ /** * Контроллер ввода штрих-кодов. */ Ext.define("Ews.controller.Barcode", { extend: "Ext.app.Controller", requires: ["Ews.util.EventUtil"], barcodePrefix: "$", barcodeSuffix: "&", //barcodeSuffixCode: 13, mode: "listen", // listen | scan value: "", init: function() { var me = this; // Событие keypress похоже надо заменить на keydown // [url]http://javascript.ru/forum/extjs/63113-ext-focusmanager-2.html[/url] Ext.getWin().on("keypress", "onWindowKeyPress", me, { capture: true }); console.group("Слежение за штрих-кодами включено."); console.log("Префикс:", me.barcodePrefix); console.log("Суффикс:", me.barcodeSuffix); console.groupEnd(); }, onWindowKeyPress: function(event) { var me = this; var keyChar = Ews.util.EventUtil.getCharFromEvent(event); if (me.mode == "scan") { if (keyChar == me.barcodeSuffix) { //if (event.keyCode == me.barcodeSuffixCode) { me.end(); } else { me.resume(keyChar); } } else { if (keyChar == me.barcodePrefix) me.begin(); } }, begin: function() { var me = this; me.value = ""; me.mode = "scan"; console.log("Начат ввод штрих-кода."); }, resume: function(keyChar) { var me = this; me.value += keyChar; console.log("Ввод штрих-кода продолжается:", keyChar, me.value); }, end: function() { var me = this; me.mode = "listen"; me.onEnterBarcode(me.value); console.log("Ввод штрих-кода завершен. Введенный код:", me.value); }, onEnterBarcode: function(barcodeValue) { var me = this; me.fireEvent("barcode", barcodeValue); } }); И вспомогательная утилитка: /* global Ext */ Ext.define("Ews.util.EventUtil", { singleton: true, /** * Получение кода символа из события keypress. * Вспомогательная функция. * event.type должен быть keypress (функция работает только с keypress). * [url]https://learn.javascript.ru/keyboard-events[/url] */ // Привести в соответствие со свойством browserEvent // [url]http://docs.sencha.com/extjs/6.0/6.0.1-classic/#!/api/Ext.event.Event-property-browserEvent[/url] getCharFromEvent: function(event) { //event = event instanceof Ext.event.Event ? event.browserEvent : event; if (event.which == null) { // IE if (event.keyCode < 32) return null; // спец. символ return String.fromCharCode(event.keyCode); } if (event.which != 0 && event.charCode != 0) { // все кроме IE if (event.which < 32) return null; // спец. символ return String.fromCharCode(event.which); // остальные } return null; // спец. символ } }); |
Часовой пояс GMT +3, время: 06:45. |