Навигация с использованием клавиатуры в ember-models-table

клавиатура

Некоторые Компоненты таблиц для разных фрейворков позволяют использовать комбинации клавиш для управления своим состоянием. Из коробки ember-models-table не дает такой возможности, однако это можно реализовать своими силами.

Для работы с события клавиатуры будет использоваться аддон ember-keyboard, который можно установить следующей командой:

1
ember i ember-keyboard

Для начала приведем список функций и сочетания клавиш, которые будут использованы:

  • Ctrl + → переход на следующию страницу
  • Ctrl + ← переход на предыдущую страницу
  • Ctrl + q очищение всех фильтров (будет работать, если фокус на момент нажатия этих кнопок не находится ни в каком поле ввода)
  • Ctrl + Shift + %N% сортирует таблицу по колонке №N
  • Ctrl + Shift + Num %N% переключает видимость колонки №N
  • Ctrl + Shift + Num - скроет все колонки
  • Ctrl + Shift + Num + покажет все колонки
  • Двойной клик мышкой по строке таблицы переведет ее в режим редактирования
  • Esc будет переводить все строки в режиме редактирования в обычный режим

Чтоб добавить весь новый функционал создадим новый Компонент, который будет расширять существующий models-table и добавим в него две Миксины из ember-keyboard:

1
ember g component my-table
1
2
3
4
import {EKOnInsertMixin, EKMixin, keyDown} from 'ember-keyboard';
import ModelsTable from 'ember-models-table/components/models-table';
 
export default ModelsTable.extend(EKMixin, EKOnInsertMixin, {});

EKMixin — это Миксина, которая обеспечивает функционал перехвата событий клавиатуры, но не включает его. EKOnInsertMixin — это Миксина, которая как раз включает данный функционал в момент вставки нашего Компонента на страницу (после события didInsertElement). В аддоне ember-keyboard есть еще пара Миксин, которые включает перехват событий клавиатуры в момент инициализации Компонента или же когда на нем есть фокус. Подробнее в документации.

Навигация по кликам Ctrl + стрелки реализуется так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import {EKOnInsertMixin, EKMixin, keyDown} from 'ember-keyboard';
import ModelsTable from 'ember-models-table/components/models-table';
import {on} from '@ember/object/evented';
import {get} from '@ember/object';
 
export default ModelsTable.extend(EKMixin, EKOnInsertMixin, {
 
  leftKeyDown: on(keyDown('ctrl+ArrowLeft'), function () {
    const pageToMove = get(this, 'currentPageNumber') - 1;
    if (pageToMove >= 1) {
      this.send('gotoCustomPage', get(this, 'currentPageNumber') - 1);
    }
  }),
 
  rightKeyDown: on(keyDown('ctrl+ArrowRight'), function () {
    const pageToMove = get(this, 'currentPageNumber') + 1;
    const pagesCount = get(this, 'pagesCount');
    if (pageToMove <= pagesCount) {
      this.send('gotoCustomPage', get(this, 'currentPageNumber') + 1);
    }
  })
});

Мы объявляем два обработчика событий leftKeyDown и rightKeyDown, которые подписываются на события нажатий комбинаций клавиш Ctrl + ArrowLeft и Ctrl + ArrowRight соответственно. Метод keyDown принимает один параметр — сочетание клавиш и возвращает имя события, на которое через on подписывается нужный метод. Имя события в данных случаях — это keydown:ArrowLeft+ctrl и keydown:ArrowRight+ctrl.

Имена клавиш Ctrl, Shift и Alt задаются «как есть» в строчной форме. Имена других клавиш можно посмотреть в code-maps#defaults.

Что же происходит в самых обработчиках? Оба они бросают событие gotoCustomPage с требуемым номером страницы, на которую надо перейти. Так же каждый из них проверяет, чтоб не было попытки выйти за пределы допустимых значений (на нулевую или же за последнюю).

Очистка всех фильтров таблицы — это тоже достаточно простая задача, решение которой занимает всего-лишь три строчки:

1
2
3
clearFiltersKeyDown: on(keyDown('ctrl+KeyQ'), function () {
  this.send('clearFilters');
}),

Подразумевается, что clearFiltersKeyDown находится внутри нашего Компонента.

Обработчик события clearFilters уже есть в models-table и он будет вызван при нажатии клавиш Ctrl + q. Обратите внимание, что в keyDown передается KeyQ, а не просто q. Если на момент нажатия данной комбинации фокус будет находится в поле ввода, то она не сработает. Это ограничение можно обойти переопределив поля ввода для фильтров, но это уже выходит за рамки небольшого обучающего материала.

Скрытие и показ всех колонок — это задачи, которые так же решаются через вызов this.send с «правильным» параметром:

1
2
3
4
5
6
7
showAllColumnsKeyDown: on(keyDown('ctrl+shift+NumpadAdd'), function () {
  this.send('showAllColumns');
}),
 
hideAllColumnsKeyDown: on(keyDown('ctrl+shift+NumpadSubtract'), function () {
  this.send('hideAllColumns');
}),

В самом models-table уже есть сответствующий функционал в виде двух обработчиков событий showAllColumns и hideAllColumns. Нам остается только «вызвать» их в нужный момент.

Скрытие/показ одной колонки и сортировка одной колонки будут рассмотрены вместе. Логика их решения очень похожа, так как под каждую колонку надо выделить свою комбинацию клавиш (основанную на номере колонки). Для простоты будем считать, что колонок меньше 10 🙂 Создание обработчиков событий можно вынести отдельно:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function getSortEventListener(num) {
  return on(keyDown(`ctrl+shift+Digit${num}`), function () {
    if (get(this, 'processedColumns.length') <= num) {
      this.send('sort', get(this, 'processedColumns').objectAt(num - 1));
    }
  });
}
 
function getToggleVisibilityEventListener(num) {
  return on(keyDown(`ctrl+shift+Numpad${num}`), function () {
    if (get(this, 'processedColumns.length') <= num) {
    	this.send('toggleHidden', get(this, 'processedColumns').objectAt(num - 1));
    }
  });
}
const MixinWithExtraListeners = {};
 
for(let i = 1; i <= 9; i++) {
  MixinWithExtraListeners[`sortByColumn${i}`] = getSortEventListener(i);
  MixinWithExtraListeners[`toggleColumn${i}`] = getToggleVisibilityEventListener(i);
}

Здесь функции getSortEventListener и getToggleVisibilityEventListener создают обработчики событий для нажатия комбинаций клавиш с разными цифрами (верхним рядом и которые справа на NumPad).

Обе эти функции можно объединить в одну, добавив еще один параметр actionName, значением которого будет sort или toggleHidden.

ember-keyboard позволяет подписываться на нажатия любых клавиш через on(keyDown()). Обработчик вызывается с одним параметром типа KeyboardEvent из которого можно понять, какая комбинация клавиш была нажата. При использовании этого варианта у вас не создается куча обработчиков под конкретные события, а есть один — «околоуниверсальный». Какой из этих способов выбрать — решать вам.

В MixinWithExtraListeners создаются все необходимые обработчики, а далее она добавляется в наш Компонент:

1
2
3
export default ModelsTable.extend(EKMixin, EKOnInsertMixin, MixinWithExtraListeners, {
  // ...
});

Из списка задач остались только две — перевод строки в режим редактирования по двойному клику и выход из него при нажатии на Esc.

Так как редактирование строки таблицы происходит в самой Компоненте строки, то требуемый функционал будем добавлять туда, а не в таблицу. Для этого создадим свой Компонент models-table/row в виде:

1
2
3
4
5
6
7
import ModelsTableRow from 'ember-models-table/components/models-table/row';
import {on} from '@ember/object/evented';
import {get} from '@ember/object';
import {EKOnFocusMixin, EKMixin, keyDown} from 'ember-keyboard';
 
export default ModelsTableRow.extend(EKMixin, EKOnFocusMixin, {
});

Обработчик двойного клика можно добавить и без ember-keyboard:

1
2
3
4
doubleClick() {
  this.send('editRow');
  this._super(...arguments);
}

Обработчик события editRow переводит ее в режим редактирования.

Отмена редактирования выглядит чуть сложнее и зависит от того, какого типа данные находятся в таблице:

1
2
3
4
cancelEditKeyDown: on(keyDown('Escape'), function() {
  this.send('cancelEditRow');
  get(this, 'record').rollbackAttributes();
})

Обработчик события cancelEditRow выводит строку из режима редактирования. Вызов get(this, 'record').rollbackAttributes() стоит использовать только если данные в таблице — это Модели из ember-data.

Все задачи из начального списка решены. Демка, как обычно, есть на ember-twiddle — Keyboard navigation demo.

Функционал, представленный в демке, я не планирую добавлять в models-table, так как он очень ситуативный и далеко не всем и не всегда нужен. Да и сами комбинации клавиш одним нужны одни, а другим — другие. Здесь я показал, что добавить поддержку клавиатуры не сложно и не занимает много времени.

, ,

Оставить комментарий

Top ↑ | Main page | Back