desy-html 10.2.2 → 11.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -36
- package/config/tailwind.config.js +217 -217
- package/docs/_global.content-placeholder.njk +7 -7
- package/docs/_global.foot.njk +14 -14
- package/docs/_global.head.njk +28 -28
- package/docs/_include.template-header.njk +387 -387
- package/docs/_macro.component-example.njk +6 -6
- package/docs/_macro.example-render.njk +330 -330
- package/docs/_macro.load-component-params.njk +2 -2
- package/docs/_macro.load-component-template.njk +3 -3
- package/docs/_macro.render-caller.njk +3 -3
- package/docs/_macro.show-code-from-file.njk +57 -57
- package/docs/_macro.show-html-from-file.njk +42 -42
- package/docs/_template.default.njk +8 -8
- package/docs/_template.examples.njk +13 -13
- package/docs/catalogo.html +26 -26
- package/docs/componentes.html +180 -180
- package/docs/ds/_ds.example.accordion.njk +109 -109
- package/docs/ds/_ds.example.border.njk +39 -39
- package/docs/ds/_ds.example.botones-alert-sm.njk +264 -264
- package/docs/ds/_ds.example.botones-alert.njk +264 -264
- package/docs/ds/_ds.example.botones-default-sm.njk +264 -264
- package/docs/ds/_ds.example.botones-default.njk +258 -258
- package/docs/ds/_ds.example.botones-primary-sm.njk +264 -264
- package/docs/ds/_ds.example.botones-primary.njk +264 -264
- package/docs/ds/_ds.example.botones-transparent-sm.njk +264 -264
- package/docs/ds/_ds.example.botones-transparent.njk +264 -264
- package/docs/ds/_ds.example.breadcrumbs.njk +65 -65
- package/docs/ds/_ds.example.card.njk +198 -198
- package/docs/ds/_ds.example.checkboxes.njk +377 -377
- package/docs/ds/_ds.example.collapsible.njk +18 -18
- package/docs/ds/_ds.example.color-de-interaccion.njk +16 -16
- package/docs/ds/_ds.example.colores-cabecera.njk +15 -15
- package/docs/ds/_ds.example.colores-de-soporte.njk +82 -82
- package/docs/ds/_ds.example.colores-neutros.njk +26 -26
- package/docs/ds/_ds.example.date-input.njk +363 -363
- package/docs/ds/_ds.example.description-list.njk +289 -289
- package/docs/ds/_ds.example.details.njk +23 -23
- package/docs/ds/_ds.example.dropdowns-default.njk +186 -186
- package/docs/ds/_ds.example.dropdowns-en-uso.njk +105 -105
- package/docs/ds/_ds.example.dropdowns-variaciones.njk +187 -187
- package/docs/ds/_ds.example.error-summary.njk +34 -34
- package/docs/ds/_ds.example.file-upload.njk +54 -54
- package/docs/ds/_ds.example.footer.njk +28 -28
- package/docs/ds/_ds.example.header-advanced.njk +70 -70
- package/docs/ds/_ds.example.header.njk +211 -211
- package/docs/ds/_ds.example.input-group.njk +242 -242
- package/docs/ds/_ds.example.input.njk +164 -164
- package/docs/ds/_ds.example.item.njk +176 -176
- package/docs/ds/_ds.example.layout-escritorio.njk +38 -38
- package/docs/ds/_ds.example.layout-movil.njk +14 -14
- package/docs/ds/_ds.example.layout-sidebar.njk +11 -11
- package/docs/ds/_ds.example.links-list.njk +170 -170
- package/docs/ds/_ds.example.listbox-default.njk +677 -677
- package/docs/ds/_ds.example.listbox-variaciones.njk +687 -687
- package/docs/ds/_ds.example.menu-horizontal.njk +66 -66
- package/docs/ds/_ds.example.menu-navigation.njk +493 -493
- package/docs/ds/_ds.example.menu-vertical.njk +129 -129
- package/docs/ds/_ds.example.menubar-en-uso.njk +244 -244
- package/docs/ds/_ds.example.menubar-variaciones.njk +785 -785
- package/docs/ds/_ds.example.modal.njk +210 -210
- package/docs/ds/_ds.example.nav.njk +158 -158
- package/docs/ds/_ds.example.notification.njk +122 -122
- package/docs/ds/_ds.example.pagination.njk +190 -190
- package/docs/ds/_ds.example.pills.njk +215 -215
- package/docs/ds/_ds.example.radios.njk +419 -419
- package/docs/ds/_ds.example.searchbar.njk +87 -87
- package/docs/ds/_ds.example.select.njk +390 -390
- package/docs/ds/_ds.example.status-item.njk +239 -239
- package/docs/ds/_ds.example.status.njk +47 -47
- package/docs/ds/_ds.example.table.njk +740 -740
- package/docs/ds/_ds.example.tabs.njk +92 -92
- package/docs/ds/_ds.example.textarea.njk +237 -237
- package/docs/ds/_ds.example.textos.njk +27 -27
- package/docs/ds/_ds.example.toggle.njk +75 -75
- package/docs/ds/_ds.example.tree.njk +456 -456
- package/docs/ds/_ds.example.typography.njk +225 -225
- package/docs/ds/_ds.macro.code-snippet.njk +32 -32
- package/docs/ds/_ds.macro.section-title.njk +2 -2
- package/docs/ds/_ds.macro.subsection-title.njk +2 -2
- package/docs/ds/_ds.section.avisos.njk +22 -22
- package/docs/ds/_ds.section.botones.njk +48 -48
- package/docs/ds/_ds.section.campo-y-area-de-texto.njk +19 -19
- package/docs/ds/_ds.section.color.njk +150 -150
- package/docs/ds/_ds.section.datos.njk +37 -37
- package/docs/ds/_ds.section.dropdowns.njk +23 -23
- package/docs/ds/_ds.section.espaciado.njk +299 -299
- package/docs/ds/_ds.section.forms.njk +68 -68
- package/docs/ds/_ds.section.informacion.njk +12 -12
- package/docs/ds/_ds.section.layout.njk +70 -70
- package/docs/ds/_ds.section.menubar.njk +18 -18
- package/docs/ds/_ds.section.mostrar-ocultar.njk +33 -33
- package/docs/ds/_ds.section.navigation.njk +57 -57
- package/docs/ds/_ds.section.textos.njk +259 -259
- package/docs/ds/_ds.section.typography.njk +31 -31
- package/docs/estilos.html +19 -19
- package/docs/examples-accordion-history.html +8 -8
- package/docs/examples-accordion.html +8 -8
- package/docs/examples-alert.html +8 -8
- package/docs/examples-breadcrumbs.html +8 -8
- package/docs/examples-button-loader.html +8 -8
- package/docs/examples-button.html +8 -8
- package/docs/examples-card.html +7 -7
- package/docs/examples-character-count.html +8 -8
- package/docs/examples-checkboxes.html +7 -7
- package/docs/examples-collapsible.html +7 -7
- package/docs/examples-date-input.html +8 -8
- package/docs/examples-datepicker.html +8 -8
- package/docs/examples-description-list.html +8 -8
- package/docs/examples-details.html +8 -8
- package/docs/examples-dialog.html +7 -7
- package/docs/examples-dropdown.html +8 -8
- package/docs/examples-error-message.html +8 -8
- package/docs/examples-error-summary.html +8 -8
- package/docs/examples-fieldset.html +8 -8
- package/docs/examples-file-upload.html +8 -8
- package/docs/examples-footer.html +8 -8
- package/docs/examples-header-advanced.html +8 -8
- package/docs/examples-header-mini.html +8 -8
- package/docs/examples-header.html +8 -8
- package/docs/examples-hint.html +8 -8
- package/docs/examples-input-group.html +8 -8
- package/docs/examples-input.html +8 -8
- package/docs/examples-item.html +8 -8
- package/docs/examples-label.html +8 -8
- package/docs/examples-links-list.html +7 -7
- package/docs/examples-listbox.html +8 -8
- package/docs/examples-media-object.html +7 -7
- package/docs/examples-menu-horizontal.html +8 -8
- package/docs/examples-menu-navigation.html +8 -8
- package/docs/examples-menu-vertical.html +7 -7
- package/docs/examples-menubar.html +7 -7
- package/docs/examples-modal.html +7 -7
- package/docs/examples-nav.html +8 -8
- package/docs/examples-notification.html +8 -8
- package/docs/examples-pagination.html +8 -8
- package/docs/examples-pill.html +8 -8
- package/docs/examples-radios.html +8 -8
- package/docs/examples-searchbar.html +8 -8
- package/docs/examples-select.html +9 -9
- package/docs/examples-skip-link.html +8 -8
- package/docs/examples-spinner.html +8 -8
- package/docs/examples-status-item.html +8 -8
- package/docs/examples-status.html +8 -8
- package/docs/examples-table-advanced.html +8 -8
- package/docs/examples-table.html +8 -8
- package/docs/examples-tabs.html +8 -8
- package/docs/examples-textarea.html +8 -8
- package/docs/examples-toggle.html +8 -8
- package/docs/examples-tooltip.html +8 -8
- package/docs/examples-tree.html +8 -8
- package/docs/index.html +679 -667
- package/docs/pagina-accesibilidad.html +109 -109
- package/docs/pagina-mapa-web.html +136 -136
- package/docs/pagina-prueba.html +94 -94
- package/docs/plantilla-con-header-advanced.html +13 -13
- package/docs/plantilla-editar-con-cabecera-fija-y-sidebar-sticky.html +153 -153
- package/docs/plantilla-editar-con-cabecera-fija.html +16 -16
- package/docs/plantilla-logueado-con-cabecera-fija-headroom.html +14 -14
- package/docs/plantilla-logueado-con-cabecera-fija.html +14 -14
- package/docs/plantilla-logueado-con-selector-de-app-y-sidebar.html +163 -163
- package/docs/plantilla-logueado-con-selector-de-app-y-subheader.html +15 -15
- package/docs/plantilla-logueado-con-selector-de-app.html +13 -13
- package/docs/plantilla-logueado-con-titulo-de-app.html +13 -13
- package/docs/plantilla-sin-loguear.html +13 -13
- package/docs/plantillas.html +88 -88
- package/docs/spinner-plantilla-con-header-advanced.html +1 -1
- package/docs/spinner-plantilla-editar-con-cabecera-fija.html +5 -5
- package/docs/spinner-plantilla-logueado-con-cabecera-fija.html +1 -1
- package/docs/spinner-plantilla-logueado-con-selector-de-app-y-subheader.html +4 -4
- package/docs/spinner-plantilla-logueado-con-titulo-de-app.html +1 -1
- package/docs/spinner-plantilla-sin-loguear.html +17 -17
- package/gulpfile.js +127 -127
- package/package.json +67 -67
- package/src/EUPL-1.2.txt +287 -287
- package/src/css/base.css +42 -42
- package/src/css/component.form-group.css +23 -23
- package/src/css/component.headroom.css +31 -31
- package/src/css/component.text.css +157 -157
- package/src/css/component.tippy-box.css +11 -11
- package/src/css/styles.css +49 -49
- package/src/js/aria/HeaderNavigation.js +55 -55
- package/src/js/aria/MenuHorizontal.js +63 -63
- package/src/js/aria/MenuVertical.js +60 -60
- package/src/js/aria/Nav.js +60 -60
- package/src/js/aria/accordion.js +264 -264
- package/src/js/aria/checkBoxes.js +52 -52
- package/src/js/aria/collapsible.js +44 -44
- package/src/js/aria/dataGrid.js +950 -950
- package/src/js/aria/notification.js +56 -56
- package/src/js/aria/radioButton.js +50 -50
- package/src/js/aria/toggle.js +61 -61
- package/src/js/aria/utils.js +128 -128
- package/src/js/cally.js +1114 -1114
- package/src/js/desy-html.js +525 -525
- package/src/js/filters/filter-caller.js +6 -6
- package/src/js/filters/filter-slugify.js +11 -11
- package/src/js/filters/highlight.js +14 -14
- package/src/js/filters/index.js +13 -13
- package/src/js/globals/get-html-code-from-example.js +31 -31
- package/src/js/globals/get-html-code-from-file.js +26 -26
- package/src/js/globals/get-nunjucks-code-from-example.js +31 -31
- package/src/js/globals/get-nunjucks-code-from-file.js +24 -24
- package/src/js/globals/index.js +14 -14
- package/src/js/headroom.min.js +6 -6
- package/src/js/index.js +73 -73
- package/src/js/popper.min.js +6 -6
- package/src/js/tippy-bundle.umd.min.js +2 -2
- package/src/templates/components/accordion/_examples.accordion.njk +386 -386
- package/src/templates/components/accordion/_macro.accordion.njk +3 -3
- package/src/templates/components/accordion/_template.accordion.njk +131 -131
- package/src/templates/components/accordion/params.accordion.yaml +125 -125
- package/src/templates/components/accordion-history/_examples.accordion-history.njk +418 -418
- package/src/templates/components/accordion-history/_macro.accordion-history.njk +3 -3
- package/src/templates/components/accordion-history/_template.accordion-history.njk +193 -193
- package/src/templates/components/accordion-history/params.accordion-history.yaml +129 -129
- package/src/templates/components/alert/_examples.alert.njk +79 -79
- package/src/templates/components/alert/_macro.alert.njk +3 -3
- package/src/templates/components/alert/_styles.alert.css +9 -9
- package/src/templates/components/alert/_template.alert.njk +16 -16
- package/src/templates/components/alert/params.alert.yaml +25 -25
- package/src/templates/components/breadcrumbs/_examples.breadcrumbs.njk +374 -374
- package/src/templates/components/breadcrumbs/_macro.breadcrumbs.njk +3 -3
- package/src/templates/components/breadcrumbs/_styles.breadcrumbs.css +69 -69
- package/src/templates/components/breadcrumbs/_template.breadcrumbs.njk +77 -77
- package/src/templates/components/breadcrumbs/params.breadcrumbs.yaml +44 -44
- package/src/templates/components/button/_examples.button.njk +289 -289
- package/src/templates/components/button/_macro.button.njk +3 -3
- package/src/templates/components/button/_styles.button.css +182 -182
- package/src/templates/components/button/_template.button.njk +49 -49
- package/src/templates/components/button/params.button.yaml +48 -48
- package/src/templates/components/button-loader/_examples.button-loader.njk +281 -281
- package/src/templates/components/button-loader/_macro.button-loader.njk +3 -3
- package/src/templates/components/button-loader/_styles.button-loader.css +198 -198
- package/src/templates/components/button-loader/_template.button-loader.njk +84 -84
- package/src/templates/components/button-loader/params.button-loader.yaml +74 -74
- package/src/templates/components/card/_examples.card.njk +300 -300
- package/src/templates/components/card/_macro.card.njk +3 -3
- package/src/templates/components/card/_template.card.njk +34 -34
- package/src/templates/components/card/params.card.yaml +112 -112
- package/src/templates/components/character-count/_examples.character-count.njk +147 -147
- package/src/templates/components/character-count/_macro.character-count.njk +5 -5
- package/src/templates/components/character-count/_template.character-count.njk +38 -38
- package/src/templates/components/character-count/params.character-count.yaml +77 -77
- package/src/templates/components/checkboxes/_examples.checkboxes.njk +734 -734
- package/src/templates/components/checkboxes/_macro.checkboxes.njk +3 -3
- package/src/templates/components/checkboxes/_styles.checkboxes.css +31 -31
- package/src/templates/components/checkboxes/_template.checkboxes.njk +138 -138
- package/src/templates/components/checkboxes/params.checkboxes.yaml +116 -116
- package/src/templates/components/collapsible/_examples.collapsible.njk +77 -77
- package/src/templates/components/collapsible/_macro.collapsible.njk +3 -3
- package/src/templates/components/collapsible/_styles.collapsible.css +33 -33
- package/src/templates/components/collapsible/_template.collapsible.njk +17 -17
- package/src/templates/components/collapsible/params.collapsible.yaml +48 -48
- package/src/templates/components/date-input/_examples.date-input.njk +500 -500
- package/src/templates/components/date-input/_macro.date-input.njk +3 -3
- package/src/templates/components/date-input/_template.date-input.njk +126 -126
- package/src/templates/components/date-input/params.date-input.yaml +97 -97
- package/src/templates/components/datepicker/_examples.datepicker.njk +346 -346
- package/src/templates/components/datepicker/_macro.datepicker.njk +3 -3
- package/src/templates/components/datepicker/_styles.datepicker.css +85 -85
- package/src/templates/components/datepicker/_template.datepicker.njk +123 -123
- package/src/templates/components/datepicker/params.datepicker.yaml +104 -104
- package/src/templates/components/description-list/_examples.description-list.njk +436 -436
- package/src/templates/components/description-list/_macro.description-list.njk +3 -3
- package/src/templates/components/description-list/_template.description-list.njk +17 -17
- package/src/templates/components/description-list/params.description-list.yaml +61 -61
- package/src/templates/components/details/_examples.details.njk +44 -44
- package/src/templates/components/details/_macro.details.njk +3 -3
- package/src/templates/components/details/_template.details.njk +17 -17
- package/src/templates/components/details/params.details.yaml +40 -40
- package/src/templates/components/dialog/_examples.dialog.njk +138 -138
- package/src/templates/components/dialog/_macro.dialog.njk +3 -3
- package/src/templates/components/dialog/_styles.dialog.css +19 -19
- package/src/templates/components/dialog/_template.dialog.njk +12 -12
- package/src/templates/components/dialog/params.dialog.yaml +25 -25
- package/src/templates/components/dropdown/_examples.dropdown.njk +114 -114
- package/src/templates/components/dropdown/_macro.dropdown.njk +3 -3
- package/src/templates/components/dropdown/_styles.dropdown.css +187 -187
- package/src/templates/components/dropdown/_template.dropdown.njk +34 -34
- package/src/templates/components/dropdown/params.dropdown.yaml +32 -32
- package/src/templates/components/error-message/_examples.error-message.njk +14 -14
- package/src/templates/components/error-message/_macro.error-message.njk +5 -5
- package/src/templates/components/error-message/_template.error-message.njk +8 -8
- package/src/templates/components/error-message/params.error-message.yaml +23 -23
- package/src/templates/components/error-summary/_examples.error-summary.njk +81 -81
- package/src/templates/components/error-summary/_macro.error-summary.njk +5 -5
- package/src/templates/components/error-summary/_template.error-summary.njk +48 -48
- package/src/templates/components/error-summary/params.error-summary.yaml +52 -52
- package/src/templates/components/fieldset/_examples.fieldset.njk +88 -88
- package/src/templates/components/fieldset/_macro.fieldset.njk +2 -2
- package/src/templates/components/fieldset/_template.fieldset.njk +46 -46
- package/src/templates/components/fieldset/params.fieldset.yaml +49 -49
- package/src/templates/components/file-upload/_examples.file-upload.njk +84 -84
- package/src/templates/components/file-upload/_macro.file-upload.njk +2 -2
- package/src/templates/components/file-upload/_template.file-upload.njk +46 -46
- package/src/templates/components/file-upload/params.file-upload.yaml +48 -48
- package/src/templates/components/footer/_examples.footer.njk +492 -492
- package/src/templates/components/footer/_macro.footer.njk +3 -3
- package/src/templates/components/footer/_styles.footer.css +43 -43
- package/src/templates/components/footer/_template.footer.njk +114 -114
- package/src/templates/components/footer/params.footer.yaml +140 -140
- package/src/templates/components/header/_examples.header.njk +535 -535
- package/src/templates/components/header/_macro.header.header__dropdown.njk +3 -3
- package/src/templates/components/header/_macro.header.header__navigation.njk +3 -3
- package/src/templates/components/header/_macro.header.header__offcanvas.njk +3 -3
- package/src/templates/components/header/_macro.header.header__offcanvasButton.njk +3 -3
- package/src/templates/components/header/_macro.header.header__subnav.njk +3 -3
- package/src/templates/components/header/_macro.header.njk +3 -3
- package/src/templates/components/header/_styles.header.css +12 -12
- package/src/templates/components/header/_template.header.header__dropdown.njk +27 -27
- package/src/templates/components/header/_template.header.header__navigation.njk +27 -27
- package/src/templates/components/header/_template.header.header__offcanvas.njk +20 -20
- package/src/templates/components/header/_template.header.header__offcanvasButton.njk +10 -10
- package/src/templates/components/header/_template.header.header__subnav.njk +33 -33
- package/src/templates/components/header/_template.header.njk +138 -138
- package/src/templates/components/header/params.header.yaml +280 -280
- package/src/templates/components/header-advanced/_examples.header-advanced.njk +1016 -1016
- package/src/templates/components/header-advanced/_macro.header-advanced.njk +3 -3
- package/src/templates/components/header-advanced/_template.header-advanced.njk +168 -168
- package/src/templates/components/header-advanced/params.header-advanced.yaml +346 -346
- package/src/templates/components/header-mini/_examples.header-mini.njk +304 -304
- package/src/templates/components/header-mini/_macro.header-mini.njk +3 -3
- package/src/templates/components/header-mini/_template.header-mini.njk +39 -39
- package/src/templates/components/header-mini/params.header-mini.yaml +80 -80
- package/src/templates/components/hint/_examples.hint.njk +14 -14
- package/src/templates/components/hint/_macro.hint.njk +3 -3
- package/src/templates/components/hint/_template.hint.njk +3 -3
- package/src/templates/components/hint/params.hint.yaml +34 -34
- package/src/templates/components/input/_examples.input.njk +309 -309
- package/src/templates/components/input/_macro.input.njk +3 -3
- package/src/templates/components/input/_styles.input.css +18 -18
- package/src/templates/components/input/_template.input.njk +54 -54
- package/src/templates/components/input/params.input.yaml +80 -80
- package/src/templates/components/input-group/_examples.input-group.njk +503 -503
- package/src/templates/components/input-group/_macro.input-group.njk +3 -3
- package/src/templates/components/input-group/_template.input-group.njk +108 -108
- package/src/templates/components/input-group/params.input-group.yaml +123 -123
- package/src/templates/components/item/_examples.item.njk +262 -262
- package/src/templates/components/item/_macro.item.njk +3 -3
- package/src/templates/components/item/_template.item.njk +73 -73
- package/src/templates/components/item/params.item.yaml +101 -101
- package/src/templates/components/label/_examples.label.njk +34 -34
- package/src/templates/components/label/_macro.label.njk +5 -5
- package/src/templates/components/label/_template.label.njk +37 -37
- package/src/templates/components/label/params.label.yaml +28 -28
- package/src/templates/components/links-list/_examples.links-list.njk +594 -594
- package/src/templates/components/links-list/_macro.links-list.njk +3 -3
- package/src/templates/components/links-list/_template.links-list.njk +118 -118
- package/src/templates/components/links-list/params.links-list.yaml +101 -101
- package/src/templates/components/listbox/_examples.listbox.njk +656 -656
- package/src/templates/components/listbox/_macro.listbox.njk +3 -3
- package/src/templates/components/listbox/_styles.listbox.css +218 -218
- package/src/templates/components/listbox/_template.listbox.njk +90 -90
- package/src/templates/components/listbox/params.listbox.yaml +85 -85
- package/src/templates/components/media-object/_examples.media-object.njk +48 -48
- package/src/templates/components/media-object/_macro.media-object.njk +3 -3
- package/src/templates/components/media-object/_template.media-object.njk +21 -21
- package/src/templates/components/media-object/params.media-object.yaml +16 -16
- package/src/templates/components/menu-horizontal/_examples.menu-horizontal.njk +514 -514
- package/src/templates/components/menu-horizontal/_macro.menu-horizontal.njk +3 -3
- package/src/templates/components/menu-horizontal/_styles.menu-horizontal.css +161 -161
- package/src/templates/components/menu-horizontal/_template.menu-horizontal.njk +36 -36
- package/src/templates/components/menu-horizontal/params.menu-horizontal.yaml +53 -53
- package/src/templates/components/menu-navigation/_examples.menu-navigation.njk +1106 -1106
- package/src/templates/components/menu-navigation/_macro.menu-navigation.njk +3 -3
- package/src/templates/components/menu-navigation/_styles.menu-navigation.css +227 -227
- package/src/templates/components/menu-navigation/_template.menu-navigation.njk +89 -89
- package/src/templates/components/menu-navigation/params.menu-navigation.yaml +86 -86
- package/src/templates/components/menu-vertical/_examples.menu-vertical.njk +739 -739
- package/src/templates/components/menu-vertical/_macro.menu-vertical.njk +3 -3
- package/src/templates/components/menu-vertical/_template.menu-vertical.njk +92 -92
- package/src/templates/components/menu-vertical/params.menu-vertical.yaml +77 -77
- package/src/templates/components/menubar/_examples.menubar.njk +1623 -1623
- package/src/templates/components/menubar/_macro.menubar.njk +3 -3
- package/src/templates/components/menubar/_styles.menubar.css +253 -253
- package/src/templates/components/menubar/_template.menubar.njk +105 -105
- package/src/templates/components/menubar/params.menubar.yaml +139 -139
- package/src/templates/components/modal/_examples.modal.njk +354 -354
- package/src/templates/components/modal/_macro.modal.njk +3 -3
- package/src/templates/components/modal/_template.modal.njk +129 -129
- package/src/templates/components/modal/params.modal.yaml +77 -77
- package/src/templates/components/nav/_examples.nav.njk +402 -402
- package/src/templates/components/nav/_macro.nav.njk +3 -3
- package/src/templates/components/nav/_template.nav.njk +53 -53
- package/src/templates/components/nav/params.nav.yaml +61 -61
- package/src/templates/components/notification/_examples.notification.njk +193 -193
- package/src/templates/components/notification/_macro.notification.njk +3 -3
- package/src/templates/components/notification/_styles.notification.css +28 -28
- package/src/templates/components/notification/_template.notification.njk +86 -86
- package/src/templates/components/notification/params.notification.yaml +101 -101
- package/src/templates/components/pagination/_examples.pagination.njk +402 -397
- package/src/templates/components/pagination/_macro.pagination.njk +3 -3
- package/src/templates/components/pagination/_template.pagination.njk +158 -153
- package/src/templates/components/pagination/params.pagination.yaml +150 -150
- package/src/templates/components/pill/_examples.pill.njk +101 -101
- package/src/templates/components/pill/_macro.pill.njk +3 -3
- package/src/templates/components/pill/_styles.pill.css +63 -63
- package/src/templates/components/pill/_template.pill.njk +38 -38
- package/src/templates/components/pill/params.pill.yaml +28 -28
- package/src/templates/components/radios/_examples.radios.njk +637 -637
- package/src/templates/components/radios/_macro.radios.njk +5 -5
- package/src/templates/components/radios/_styles.radios.css +31 -31
- package/src/templates/components/radios/_template.radios.njk +134 -134
- package/src/templates/components/radios/params.radios.yaml +104 -104
- package/src/templates/components/searchbar/_examples.searchbar.njk +98 -98
- package/src/templates/components/searchbar/_macro.searchbar.njk +3 -3
- package/src/templates/components/searchbar/_template.searchbar.njk +46 -46
- package/src/templates/components/searchbar/params.searchbar.yaml +46 -46
- package/src/templates/components/select/_examples.select.njk +336 -336
- package/src/templates/components/select/_macro.select.njk +5 -5
- package/src/templates/components/select/_styles.select.css +47 -47
- package/src/templates/components/select/_template.select.njk +70 -70
- package/src/templates/components/select/params.select.yaml +93 -93
- package/src/templates/components/skip-link/_examples.skip-link.njk +19 -19
- package/src/templates/components/skip-link/_macro.skip-link.njk +3 -3
- package/src/templates/components/skip-link/_styles.skip-link.css +13 -13
- package/src/templates/components/skip-link/_template.skip-link.njk +4 -4
- package/src/templates/components/skip-link/params.skip-link.yaml +20 -20
- package/src/templates/components/spinner/_examples.spinner.njk +52 -52
- package/src/templates/components/spinner/_macro.spinner.njk +3 -3
- package/src/templates/components/spinner/_styles.spinner.css +32 -32
- package/src/templates/components/spinner/_template.spinner.njk +8 -8
- package/src/templates/components/spinner/params.spinner.yaml +12 -12
- package/src/templates/components/status/_examples.status.njk +49 -49
- package/src/templates/components/status/_macro.status.njk +3 -3
- package/src/templates/components/status/_template.status.njk +23 -23
- package/src/templates/components/status/params.status.yaml +24 -24
- package/src/templates/components/status-item/_examples.status-item.njk +245 -245
- package/src/templates/components/status-item/_macro.status-item.njk +3 -3
- package/src/templates/components/status-item/_template.status-item.njk +99 -99
- package/src/templates/components/status-item/params.status-item.yaml +106 -106
- package/src/templates/components/table/_examples.table.njk +887 -887
- package/src/templates/components/table/_macro.table.njk +3 -3
- package/src/templates/components/table/_template.table.njk +68 -68
- package/src/templates/components/table/params.table.yaml +126 -126
- package/src/templates/components/table-advanced/_examples.table-advanced.njk +875 -875
- package/src/templates/components/table-advanced/_macro.table-advanced.njk +3 -3
- package/src/templates/components/table-advanced/_styles.table-advanced.css +65 -65
- package/src/templates/components/table-advanced/_template.table-advanced.njk +207 -207
- package/src/templates/components/table-advanced/params.table-advanced.yaml +156 -156
- package/src/templates/components/tabs/_examples.tabs.njk +473 -473
- package/src/templates/components/tabs/_macro.tabs.njk +3 -3
- package/src/templates/components/tabs/_styles.tabs.css +55 -55
- package/src/templates/components/tabs/_template.tabs.njk +70 -70
- package/src/templates/components/tabs/params.tabs.yaml +79 -79
- package/src/templates/components/textarea/_examples.textarea.njk +131 -131
- package/src/templates/components/textarea/_macro.textarea.njk +5 -5
- package/src/templates/components/textarea/_template.textarea.njk +48 -48
- package/src/templates/components/textarea/params.textarea.yaml +64 -64
- package/src/templates/components/toggle/_examples.toggle.njk +188 -188
- package/src/templates/components/toggle/_macro.toggle.njk +3 -3
- package/src/templates/components/toggle/_styles.toggle.css +31 -31
- package/src/templates/components/toggle/_template.toggle.njk +27 -27
- package/src/templates/components/toggle/params.toggle.yaml +69 -69
- package/src/templates/components/tooltip/_examples.tooltip.njk +86 -86
- package/src/templates/components/tooltip/_macro.tooltip.njk +3 -3
- package/src/templates/components/tooltip/_template.tooltip.njk +39 -39
- package/src/templates/components/tooltip/params.tooltip.yaml +40 -40
- package/src/templates/components/tree/_examples.tree.njk +2261 -2261
- package/src/templates/components/tree/_macro.tree.njk +3 -3
- package/src/templates/components/tree/_styles.tree.css +53 -53
- package/src/templates/components/tree/_template.tree.njk +182 -182
- package/src/templates/components/tree/params.tree.yaml +167 -167
- package/src/templates/includes/_abrir-notificaciones-extra.njk +2 -2
- package/src/templates/includes/_abrir-notificaciones.njk +2 -2
- package/src/templates/includes/_acciones-de-cabecera.njk +28 -28
- package/src/templates/includes/_ejemplo-titulo-h2-parrafo.njk +4 -4
- package/src/templates/includes/_ejemplo-titulo-parrafo.njk +4 -4
- package/src/templates/includes/_test-include.njk +13 -13
- package/src/templates/pages/_page.foot-headroom.njk +33 -33
- package/src/templates/pages/_page.foot.njk +8 -8
- package/src/templates/pages/_page.footer.njk +19 -19
- package/src/templates/pages/_page.head.njk +12 -12
- package/src/templates/pages/_page.notification-edit-inner-content.njk +31 -31
- package/src/templates/pages/_page.notification-edit.njk +30 -30
- package/src/templates/pages/_page.notification-footer.njk +32 -32
- package/src/templates/pages/_page.notification-header-fixed.njk +30 -30
- package/src/templates/pages/_page.notification-header.njk +31 -31
- package/src/templates/pages/_page.sidebar-content.njk +20 -20
- package/src/templates/pages/_page.spinner-block.njk +14 -14
- package/src/templates/pages/_page.spinner-show.njk +15 -15
- package/src/templates/pages/_page.spinner.njk +15 -15
- package/src/templates/pages/_template.edit-fixed-with-sticky-sidebar.njk +36 -36
- package/src/templates/pages/_template.edit-fixed.njk +74 -74
- package/src/templates/pages/_template.home.njk +111 -111
- package/src/templates/pages/_template.logged-out.njk +56 -56
- package/src/templates/pages/_template.logged-selector-fixed-headroom.njk +198 -198
- package/src/templates/pages/_template.logged-selector-fixed.njk +195 -195
- package/src/templates/pages/_template.logged-selector-subheader.njk +80 -80
- package/src/templates/pages/_template.logged-selector-with-sidebar.njk +28 -28
- package/src/templates/pages/_template.logged-selector.njk +195 -195
- package/src/templates/pages/_template.logged.njk +141 -141
- package/src/templates/pages/_template.mfe-iframe-content.njk +31 -31
- package/src/templates/pages/_template.mfe.njk +83 -83
- package/src/templates/pages/_template.test.njk +48 -48
- package/src/templates/pages/_template.with-header-advanced.njk +311 -311
package/src/js/aria/dataGrid.js
CHANGED
|
@@ -1,950 +1,950 @@
|
|
|
1
|
-
export function dataGrid(aria) {
|
|
2
|
-
/*
|
|
3
|
-
* This content is licensed according to the W3C Software License at
|
|
4
|
-
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
|
|
5
|
-
* Original source:
|
|
6
|
-
* https://www.w3.org/TR/wai-aria-practices-1.1/examples/grid/js/dataGrid.js
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @namespace aria
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @desc
|
|
15
|
-
* Values for aria-sort
|
|
16
|
-
*/
|
|
17
|
-
aria.SortType = {
|
|
18
|
-
ASCENDING: 'ascending',
|
|
19
|
-
DESCENDING: 'descending',
|
|
20
|
-
NONE: 'none'
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @desc
|
|
25
|
-
* DOM Selectors to find the grid components
|
|
26
|
-
*/
|
|
27
|
-
aria.GridSelector = {
|
|
28
|
-
ROW: 'tr, [role="row"]',
|
|
29
|
-
CELL: 'th, td, [role="gridcell"]',
|
|
30
|
-
SCROLL_ROW: 'tr:not([data-fixed]), [role="row"]',
|
|
31
|
-
SORT_HEADER: 'th[aria-sort]',
|
|
32
|
-
TABBABLE: '[tabindex="0"]'
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @desc
|
|
37
|
-
* CSS Class names
|
|
38
|
-
*/
|
|
39
|
-
aria.CSSClass = {
|
|
40
|
-
HIDDEN: 'hidden'
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @constructor
|
|
45
|
-
*
|
|
46
|
-
* @desc
|
|
47
|
-
* Grid object representing the state and interactions for a grid widget
|
|
48
|
-
*
|
|
49
|
-
* Assumptions:
|
|
50
|
-
* All focusable cells initially have tabindex="-1"
|
|
51
|
-
* Produces a fully filled in mxn grid (with no holes)
|
|
52
|
-
*
|
|
53
|
-
* @param gridNode
|
|
54
|
-
* The DOM node pointing to the grid
|
|
55
|
-
*/
|
|
56
|
-
aria.Grid = function (gridNode) {
|
|
57
|
-
this.navigationDisabled = false;
|
|
58
|
-
this.gridNode = gridNode;
|
|
59
|
-
this.paginationEnabled = this.gridNode.hasAttribute('data-per-page');
|
|
60
|
-
this.shouldWrapCols = this.gridNode.hasAttribute('data-wrap-cols');
|
|
61
|
-
this.shouldWrapRows = this.gridNode.hasAttribute('data-wrap-rows');
|
|
62
|
-
this.shouldRestructure = this.gridNode.hasAttribute('data-restructure');
|
|
63
|
-
this.topIndex = 0;
|
|
64
|
-
|
|
65
|
-
this.keysIndicator = document.getElementById('arrow-keys-indicator');
|
|
66
|
-
|
|
67
|
-
aria.Utils.bindMethods(this,
|
|
68
|
-
'checkFocusChange', 'checkPageChange', 'checkRestructureGrid',
|
|
69
|
-
'delegateButtonHandler', 'focusClickedCell', 'restructureGrid',
|
|
70
|
-
'showKeysIndicator', 'hideKeysIndicator');
|
|
71
|
-
this.setupFocusGrid();
|
|
72
|
-
this.setFocusPointer(0, 0);
|
|
73
|
-
|
|
74
|
-
if (this.paginationEnabled) {
|
|
75
|
-
this.setupPagination();
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
this.perPage = this.grid.length;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
this.registerEvents();
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* @desc
|
|
86
|
-
* Creates a 2D array of the focusable cells in the grid.
|
|
87
|
-
*/
|
|
88
|
-
aria.Grid.prototype.setupFocusGrid = function () {
|
|
89
|
-
this.grid = [];
|
|
90
|
-
|
|
91
|
-
Array.prototype.forEach.call(
|
|
92
|
-
this.gridNode.querySelectorAll(aria.GridSelector.ROW),
|
|
93
|
-
(function (row) {
|
|
94
|
-
var rowCells = [];
|
|
95
|
-
|
|
96
|
-
Array.prototype.forEach.call(
|
|
97
|
-
row.querySelectorAll(aria.GridSelector.CELL),
|
|
98
|
-
(function (cell) {
|
|
99
|
-
var focusableSelector = '[tabindex]';
|
|
100
|
-
|
|
101
|
-
if (aria.Utils.matches(cell, focusableSelector)) {
|
|
102
|
-
rowCells.push(cell);
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
var focusableCell = cell.querySelector(focusableSelector);
|
|
106
|
-
|
|
107
|
-
if (focusableCell) {
|
|
108
|
-
rowCells.push(focusableCell);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}).bind(this)
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
if (rowCells.length) {
|
|
115
|
-
this.grid.push(rowCells);
|
|
116
|
-
}
|
|
117
|
-
}).bind(this)
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
if (this.paginationEnabled) {
|
|
121
|
-
this.setupIndices();
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* @desc
|
|
127
|
-
* If possible, set focus pointer to the cell with the specified coordinates
|
|
128
|
-
*
|
|
129
|
-
* @param row
|
|
130
|
-
* The index of the cell's row
|
|
131
|
-
*
|
|
132
|
-
* @param col
|
|
133
|
-
* The index of the cell's column
|
|
134
|
-
*
|
|
135
|
-
* @returns
|
|
136
|
-
* Returns whether or not the focus could be set on the cell.
|
|
137
|
-
*/
|
|
138
|
-
aria.Grid.prototype.setFocusPointer = function (row, col) {
|
|
139
|
-
if (!this.isValidCell(row, col)) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (this.isHidden(row, col)) {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (!isNaN(this.focusedRow) && !isNaN(this.focusedCol)) {
|
|
148
|
-
this.grid[this.focusedRow][this.focusedCol].setAttribute('tabindex', -1);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.grid[row][col]
|
|
152
|
-
.removeEventListener('focus', this.showKeysIndicator);
|
|
153
|
-
this.grid[row][col]
|
|
154
|
-
.removeEventListener('blur', this.hideKeysIndicator);
|
|
155
|
-
|
|
156
|
-
// Disable navigation if focused on an input
|
|
157
|
-
this.navigationDisabled = aria.Utils.matches(this.grid[row][col], 'input');
|
|
158
|
-
|
|
159
|
-
this.grid[row][col].setAttribute('tabindex', 0);
|
|
160
|
-
this.focusedRow = row;
|
|
161
|
-
this.focusedCol = col;
|
|
162
|
-
|
|
163
|
-
this.grid[row][col]
|
|
164
|
-
.addEventListener('focus', this.showKeysIndicator);
|
|
165
|
-
this.grid[row][col]
|
|
166
|
-
.addEventListener('blur', this.hideKeysIndicator);
|
|
167
|
-
|
|
168
|
-
return true;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* @param row
|
|
173
|
-
* The index of the cell's row
|
|
174
|
-
*
|
|
175
|
-
* @param col
|
|
176
|
-
* The index of the cell's column
|
|
177
|
-
*
|
|
178
|
-
* @returns
|
|
179
|
-
* Returns whether or not the coordinates are within the grid's boundaries.
|
|
180
|
-
*/
|
|
181
|
-
aria.Grid.prototype.isValidCell = function (row, col) {
|
|
182
|
-
return (
|
|
183
|
-
!isNaN(row) &&
|
|
184
|
-
!isNaN(col) &&
|
|
185
|
-
row >= 0 &&
|
|
186
|
-
col >= 0 &&
|
|
187
|
-
this.grid &&
|
|
188
|
-
this.grid.length &&
|
|
189
|
-
row < this.grid.length &&
|
|
190
|
-
col < this.grid[row].length
|
|
191
|
-
);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* @param row
|
|
196
|
-
* The index of the cell's row
|
|
197
|
-
*
|
|
198
|
-
* @param col
|
|
199
|
-
* The index of the cell's column
|
|
200
|
-
*
|
|
201
|
-
* @returns
|
|
202
|
-
* Returns whether or not the cell has been hidden.
|
|
203
|
-
*/
|
|
204
|
-
aria.Grid.prototype.isHidden = function (row, col) {
|
|
205
|
-
var cell = this.gridNode.querySelectorAll(aria.GridSelector.ROW)[row]
|
|
206
|
-
.querySelectorAll(aria.GridSelector.CELL)[col];
|
|
207
|
-
return aria.Utils.hasClass(cell, aria.CSSClass.HIDDEN);
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* @desc
|
|
212
|
-
* Clean up grid events
|
|
213
|
-
*/
|
|
214
|
-
aria.Grid.prototype.clearEvents = function () {
|
|
215
|
-
this.gridNode.removeEventListener('keydown', this.checkFocusChange);
|
|
216
|
-
this.gridNode.removeEventListener('keydown', this.delegateButtonHandler);
|
|
217
|
-
this.gridNode.removeEventListener('click', this.focusClickedCell);
|
|
218
|
-
this.gridNode.removeEventListener('click', this.delegateButtonHandler);
|
|
219
|
-
|
|
220
|
-
if (this.paginationEnabled) {
|
|
221
|
-
this.gridNode.removeEventListener('keydown', this.checkPageChange);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (this.shouldRestructure) {
|
|
225
|
-
window.removeEventListener('resize', this.checkRestructureGrid);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
this.grid[this.focusedRow][this.focusedCol]
|
|
229
|
-
.removeEventListener('focus', this.showKeysIndicator);
|
|
230
|
-
this.grid[this.focusedRow][this.focusedCol]
|
|
231
|
-
.removeEventListener('blur', this.hideKeysIndicator);
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* @desc
|
|
236
|
-
* Register grid events
|
|
237
|
-
*/
|
|
238
|
-
aria.Grid.prototype.registerEvents = function () {
|
|
239
|
-
this.clearEvents();
|
|
240
|
-
|
|
241
|
-
this.gridNode.addEventListener('keydown', this.checkFocusChange);
|
|
242
|
-
this.gridNode.addEventListener('keydown', this.delegateButtonHandler);
|
|
243
|
-
this.gridNode.addEventListener('click', this.focusClickedCell);
|
|
244
|
-
this.gridNode.addEventListener('click', this.delegateButtonHandler);
|
|
245
|
-
|
|
246
|
-
if (this.paginationEnabled) {
|
|
247
|
-
this.gridNode.addEventListener('keydown', this.checkPageChange);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (this.shouldRestructure) {
|
|
251
|
-
window.addEventListener('resize', this.checkRestructureGrid);
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* @desc
|
|
257
|
-
* Focus on the cell in the specified row and column
|
|
258
|
-
*
|
|
259
|
-
* @param row
|
|
260
|
-
* The index of the cell's row
|
|
261
|
-
*
|
|
262
|
-
* @param col
|
|
263
|
-
* The index of the cell's column
|
|
264
|
-
*/
|
|
265
|
-
aria.Grid.prototype.focusCell = function (row, col) {
|
|
266
|
-
if (this.setFocusPointer(row, col)) {
|
|
267
|
-
this.grid[row][col].focus();
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
aria.Grid.prototype.showKeysIndicator = function () {
|
|
272
|
-
if (this.keysIndicator) {
|
|
273
|
-
aria.Utils.removeClass(this.keysIndicator, 'hidden');
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
aria.Grid.prototype.hideKeysIndicator = function () {
|
|
278
|
-
if (this.keysIndicator &&
|
|
279
|
-
this.grid[this.focusedRow][this.focusedCol].tabIndex === 0) {
|
|
280
|
-
aria.Utils.addClass(this.keysIndicator, 'hidden');
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* @desc
|
|
286
|
-
* Triggered on keydown. Checks if an arrow key was pressed, and (if possible)
|
|
287
|
-
* moves focus to the next valid cell in the direction of the arrow key.
|
|
288
|
-
*
|
|
289
|
-
* @param event
|
|
290
|
-
* Keydown event
|
|
291
|
-
*/
|
|
292
|
-
aria.Grid.prototype.checkFocusChange = function (event) {
|
|
293
|
-
if (!event || this.navigationDisabled) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
this.findFocusedItem(event.target);
|
|
298
|
-
|
|
299
|
-
var key = event.which || event.keyCode;
|
|
300
|
-
var rowCaret = this.focusedRow;
|
|
301
|
-
var colCaret = this.focusedCol;
|
|
302
|
-
var nextCell;
|
|
303
|
-
|
|
304
|
-
switch (key) {
|
|
305
|
-
case aria.KeyCode.UP:
|
|
306
|
-
nextCell = this.getNextVisibleCell(0, -1);
|
|
307
|
-
rowCaret = nextCell.row;
|
|
308
|
-
colCaret = nextCell.col;
|
|
309
|
-
break;
|
|
310
|
-
case aria.KeyCode.DOWN:
|
|
311
|
-
nextCell = this.getNextVisibleCell(0, 1);
|
|
312
|
-
rowCaret = nextCell.row;
|
|
313
|
-
colCaret = nextCell.col;
|
|
314
|
-
break;
|
|
315
|
-
case aria.KeyCode.LEFT:
|
|
316
|
-
nextCell = this.getNextVisibleCell(-1, 0);
|
|
317
|
-
rowCaret = nextCell.row;
|
|
318
|
-
colCaret = nextCell.col;
|
|
319
|
-
break;
|
|
320
|
-
case aria.KeyCode.RIGHT:
|
|
321
|
-
nextCell = this.getNextVisibleCell(1, 0);
|
|
322
|
-
rowCaret = nextCell.row;
|
|
323
|
-
colCaret = nextCell.col;
|
|
324
|
-
break;
|
|
325
|
-
case aria.KeyCode.HOME:
|
|
326
|
-
if (event.ctrlKey) {
|
|
327
|
-
rowCaret = 0;
|
|
328
|
-
}
|
|
329
|
-
colCaret = 0;
|
|
330
|
-
break;
|
|
331
|
-
case aria.KeyCode.END:
|
|
332
|
-
if (event.ctrlKey) {
|
|
333
|
-
rowCaret = this.grid.length - 1;
|
|
334
|
-
}
|
|
335
|
-
colCaret = this.grid[this.focusedRow].length - 1;
|
|
336
|
-
break;
|
|
337
|
-
default:
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (this.paginationEnabled) {
|
|
342
|
-
if (rowCaret < this.topIndex) {
|
|
343
|
-
this.showFromRow(rowCaret, true);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (rowCaret >= this.topIndex + this.perPage) {
|
|
347
|
-
this.showFromRow(rowCaret, false);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
this.focusCell(rowCaret, colCaret);
|
|
352
|
-
event.preventDefault();
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* @desc
|
|
357
|
-
* Reset focused row and col if it doesn't match focusedRow and focusedCol
|
|
358
|
-
*
|
|
359
|
-
* @param focusedTarget
|
|
360
|
-
* Element that is currently focused by browser
|
|
361
|
-
*/
|
|
362
|
-
aria.Grid.prototype.findFocusedItem = function (focusedTarget) {
|
|
363
|
-
var focusedCell = this.grid[this.focusedRow][this.focusedCol];
|
|
364
|
-
|
|
365
|
-
if (focusedCell === focusedTarget ||
|
|
366
|
-
focusedCell.contains(focusedTarget)) {
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
for (var i = 0; i < this.grid.length; i++) {
|
|
371
|
-
for (var j = 0; j < this.grid[i].length; j++) {
|
|
372
|
-
if (this.grid[i][j] === focusedTarget ||
|
|
373
|
-
this.grid[i][j].contains(focusedTarget)) {
|
|
374
|
-
this.setFocusPointer(i, j);
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* @desc
|
|
383
|
-
* Triggered on click. Finds the cell that was clicked on and focuses on it.
|
|
384
|
-
*
|
|
385
|
-
* @param event
|
|
386
|
-
* Keydown event
|
|
387
|
-
*/
|
|
388
|
-
aria.Grid.prototype.focusClickedCell = function (event) {
|
|
389
|
-
var clickedGridCell = this.findClosest(event.target, '[tabindex]');
|
|
390
|
-
|
|
391
|
-
for (var row = 0; row < this.grid.length; row++) {
|
|
392
|
-
for (var col = 0; col < this.grid[row].length; col++) {
|
|
393
|
-
if (this.grid[row][col] === clickedGridCell) {
|
|
394
|
-
this.setFocusPointer(row, col);
|
|
395
|
-
|
|
396
|
-
if (!aria.Utils.matches(clickedGridCell, 'button[aria-haspopup]')) {
|
|
397
|
-
// Don't focus if it's a menu button (focus should be set to menu)
|
|
398
|
-
this.focusCell(row, col);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* @desc
|
|
409
|
-
* Triggered on click. Checks if user clicked on a header with aria-sort.
|
|
410
|
-
* If so, it sorts the column based on the aria-sort attribute.
|
|
411
|
-
*
|
|
412
|
-
* @param event
|
|
413
|
-
* Keydown event
|
|
414
|
-
*/
|
|
415
|
-
aria.Grid.prototype.delegateButtonHandler = function (event) {
|
|
416
|
-
var key = event.which || event.keyCode;
|
|
417
|
-
var target = event.target;
|
|
418
|
-
var isClickEvent = (event.type === 'click');
|
|
419
|
-
|
|
420
|
-
if (!target) {
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (
|
|
425
|
-
target.parentNode &&
|
|
426
|
-
target.parentNode.matches('th[aria-sort]') &&
|
|
427
|
-
(
|
|
428
|
-
isClickEvent ||
|
|
429
|
-
key === aria.KeyCode.SPACE ||
|
|
430
|
-
key === aria.KeyCode.RETURN
|
|
431
|
-
)
|
|
432
|
-
) {
|
|
433
|
-
event.preventDefault();
|
|
434
|
-
this.handleSort(target.parentNode);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
if (
|
|
438
|
-
aria.Utils.matches(target, '.editable-text, .edit-text-button') &&
|
|
439
|
-
(
|
|
440
|
-
isClickEvent ||
|
|
441
|
-
key === aria.KeyCode.RETURN
|
|
442
|
-
)
|
|
443
|
-
) {
|
|
444
|
-
event.preventDefault();
|
|
445
|
-
this.toggleEditMode(
|
|
446
|
-
this.findClosest(target, '.editable-text'),
|
|
447
|
-
true,
|
|
448
|
-
true
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (
|
|
453
|
-
aria.Utils.matches(target, '.edit-text-input') &&
|
|
454
|
-
(
|
|
455
|
-
key === aria.KeyCode.RETURN ||
|
|
456
|
-
key === aria.KeyCode.ESC
|
|
457
|
-
)
|
|
458
|
-
) {
|
|
459
|
-
event.preventDefault();
|
|
460
|
-
this.toggleEditMode(
|
|
461
|
-
this.findClosest(target, '.editable-text'),
|
|
462
|
-
false,
|
|
463
|
-
key === aria.KeyCode.RETURN
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* @desc
|
|
470
|
-
* Toggles the mode of an editable cell between displaying the edit button
|
|
471
|
-
* and displaying the editable input.
|
|
472
|
-
*
|
|
473
|
-
* @param editCell
|
|
474
|
-
* Cell to toggle
|
|
475
|
-
*
|
|
476
|
-
* @param toggleOn
|
|
477
|
-
* Whether to show or hide edit input
|
|
478
|
-
*
|
|
479
|
-
* @param updateText
|
|
480
|
-
* Whether or not to update the button text with the input text
|
|
481
|
-
*/
|
|
482
|
-
aria.Grid.prototype.toggleEditMode = function (editCell, toggleOn, updateText) {
|
|
483
|
-
var onClassName = toggleOn ? 'edit-text-input' : 'edit-text-button';
|
|
484
|
-
var offClassName = toggleOn ? 'edit-text-button' : 'edit-text-input';
|
|
485
|
-
var onNode = editCell.querySelector('.' + onClassName);
|
|
486
|
-
var offNode = editCell.querySelector('.' + offClassName);
|
|
487
|
-
|
|
488
|
-
if (toggleOn) {
|
|
489
|
-
onNode.value = offNode.innerText;
|
|
490
|
-
}
|
|
491
|
-
else if (updateText) {
|
|
492
|
-
onNode.innerText = offNode.value;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
aria.Utils.addClass(offNode, aria.CSSClass.HIDDEN);
|
|
496
|
-
aria.Utils.removeClass(onNode, aria.CSSClass.HIDDEN);
|
|
497
|
-
offNode.setAttribute('tabindex', -1);
|
|
498
|
-
onNode.setAttribute('tabindex', 0);
|
|
499
|
-
onNode.focus();
|
|
500
|
-
this.grid[this.focusedRow][this.focusedCol] = onNode;
|
|
501
|
-
this.navigationDisabled = toggleOn;
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* @desc
|
|
506
|
-
* Sorts the column below the header node, based on the aria-sort attribute.
|
|
507
|
-
* aria-sort="none" => aria-sort="ascending"
|
|
508
|
-
* aria-sort="ascending" => aria-sort="descending"
|
|
509
|
-
* All other headers with aria-sort are reset to "none"
|
|
510
|
-
*
|
|
511
|
-
* Note: This implementation assumes that there is no pagination on the grid.
|
|
512
|
-
*
|
|
513
|
-
* @param headerNode
|
|
514
|
-
* Header DOM node
|
|
515
|
-
*/
|
|
516
|
-
aria.Grid.prototype.handleSort = function (headerNode) {
|
|
517
|
-
var columnIndex = headerNode.cellIndex;
|
|
518
|
-
var sortType = headerNode.getAttribute('aria-sort');
|
|
519
|
-
|
|
520
|
-
if (sortType === aria.SortType.ASCENDING) {
|
|
521
|
-
sortType = aria.SortType.DESCENDING;
|
|
522
|
-
}
|
|
523
|
-
else {
|
|
524
|
-
sortType = aria.SortType.ASCENDING;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
var comparator = function (row1, row2) {
|
|
528
|
-
if(row1.children[columnIndex].classList.contains('align-top') || row2.children[columnIndex].classList.contains('align-top')) {
|
|
529
|
-
return
|
|
530
|
-
}
|
|
531
|
-
var row1Text = row1.children[columnIndex].innerText;
|
|
532
|
-
var row2Text = row2.children[columnIndex].innerText;
|
|
533
|
-
var row1Value = parseInt(row1Text) ? parseInt(row1Text.replace(/[^0-9\.]+/g, '')) : row1Text
|
|
534
|
-
var row2Value = parseInt(row2Text) ? parseInt(row2Text.replace(/[^0-9\.]+/g, '')) : row2Text
|
|
535
|
-
|
|
536
|
-
var orderValue = parseInt(row1Text) ? 'numbers' : 'strings'
|
|
537
|
-
|
|
538
|
-
if (sortType === aria.SortType.ASCENDING && orderValue === 'numbers') {
|
|
539
|
-
return row1Value - row2Value;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
if (sortType === aria.SortType.DESCENDING && orderValue === 'numbers') {
|
|
543
|
-
return row2Value - row1Value;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (sortType === aria.SortType.ASCENDING && orderValue === 'strings') {
|
|
547
|
-
return row1Value.toString().localeCompare(row2Value);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
if (sortType === aria.SortType.DESCENDING && orderValue === 'strings') {
|
|
551
|
-
return row2Value.toString().localeCompare(row1Value);
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
this.sortRows(comparator);
|
|
557
|
-
this.setupFocusGrid();
|
|
558
|
-
|
|
559
|
-
Array.prototype.forEach.call(
|
|
560
|
-
this.gridNode.querySelectorAll(aria.GridSelector.SORT_HEADER),
|
|
561
|
-
function (headerCell) {
|
|
562
|
-
headerCell.setAttribute('aria-sort', aria.SortType.NONE);
|
|
563
|
-
}
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
headerNode.setAttribute('aria-sort', sortType);
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
/**
|
|
570
|
-
* @desc
|
|
571
|
-
* Sorts the grid's rows according to the specified compareFn
|
|
572
|
-
*
|
|
573
|
-
* @param compareFn
|
|
574
|
-
* Comparison function to sort the rows
|
|
575
|
-
*/
|
|
576
|
-
aria.Grid.prototype.sortRows = function (compareFn) {
|
|
577
|
-
var rows = this.gridNode.querySelectorAll("tbody tr");
|
|
578
|
-
var rowWrapper = this.gridNode.querySelector('tbody');
|
|
579
|
-
var dataRows = Array.prototype.slice.call(rows, 1);
|
|
580
|
-
|
|
581
|
-
dataRows.sort(compareFn);
|
|
582
|
-
|
|
583
|
-
dataRows.forEach((function (row) {
|
|
584
|
-
rowWrapper.appendChild(row);
|
|
585
|
-
}).bind(this));
|
|
586
|
-
};
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* @desc
|
|
590
|
-
* Adds aria-rowindex and aria-colindex to the cells in the grid
|
|
591
|
-
*/
|
|
592
|
-
aria.Grid.prototype.setupIndices = function () {
|
|
593
|
-
var rows = this.gridNode.querySelectorAll(aria.GridSelector.ROW);
|
|
594
|
-
|
|
595
|
-
for (var row = 0; row < rows.length; row++) {
|
|
596
|
-
var cols = rows[row].querySelectorAll(aria.GridSelector.CELL);
|
|
597
|
-
rows[row].setAttribute('aria-rowindex', row + 1);
|
|
598
|
-
|
|
599
|
-
for (var col = 0; col < cols.length; col++) {
|
|
600
|
-
cols[col].setAttribute('aria-colindex', col + 1);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* @desc
|
|
608
|
-
* Determines the per page attribute of the grid, and shows/hides rows
|
|
609
|
-
* accordingly.
|
|
610
|
-
*/
|
|
611
|
-
aria.Grid.prototype.setupPagination = function () {
|
|
612
|
-
this.onPaginationChange = this.onPaginationChange || function () {};
|
|
613
|
-
this.perPage = parseInt(this.gridNode.getAttribute('data-per-page'));
|
|
614
|
-
this.showFromRow(0, true);
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
aria.Grid.prototype.setPaginationChangeHandler = function (onPaginationChange) {
|
|
618
|
-
this.onPaginationChange = onPaginationChange;
|
|
619
|
-
};
|
|
620
|
-
|
|
621
|
-
/**
|
|
622
|
-
* @desc
|
|
623
|
-
* Check if page up or page down was pressed, and show the next page if so.
|
|
624
|
-
*
|
|
625
|
-
* @param event
|
|
626
|
-
* Keydown event
|
|
627
|
-
*/
|
|
628
|
-
aria.Grid.prototype.checkPageChange = function (event) {
|
|
629
|
-
if (!event) {
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
var key = event.which || event.keyCode;
|
|
634
|
-
|
|
635
|
-
if (key === aria.KeyCode.PAGE_UP) {
|
|
636
|
-
event.preventDefault();
|
|
637
|
-
this.movePageUp();
|
|
638
|
-
}
|
|
639
|
-
else if (key === aria.KeyCode.PAGE_DOWN) {
|
|
640
|
-
event.preventDefault();
|
|
641
|
-
this.movePageDown();
|
|
642
|
-
}
|
|
643
|
-
};
|
|
644
|
-
|
|
645
|
-
aria.Grid.prototype.movePageUp = function () {
|
|
646
|
-
var startIndex = Math.max(this.perPage - 1, this.topIndex - 1);
|
|
647
|
-
this.showFromRow(startIndex, false);
|
|
648
|
-
this.focusCell(startIndex, this.focusedCol);
|
|
649
|
-
};
|
|
650
|
-
|
|
651
|
-
aria.Grid.prototype.movePageDown = function () {
|
|
652
|
-
var startIndex = this.topIndex + this.perPage;
|
|
653
|
-
this.showFromRow(startIndex, true);
|
|
654
|
-
this.focusCell(startIndex, this.focusedCol);
|
|
655
|
-
};
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* @desc
|
|
659
|
-
* Scroll the specified row into view in the specified direction
|
|
660
|
-
*
|
|
661
|
-
* @param startIndex
|
|
662
|
-
* Row index to use as the start index
|
|
663
|
-
*
|
|
664
|
-
* @param scrollDown
|
|
665
|
-
* Whether to scroll the new page above or below the row index
|
|
666
|
-
*/
|
|
667
|
-
aria.Grid.prototype.showFromRow = function (startIndex, scrollDown) {
|
|
668
|
-
var dataRows =
|
|
669
|
-
this.gridNode.querySelectorAll(aria.GridSelector.SCROLL_ROW);
|
|
670
|
-
var reachedTop = false;
|
|
671
|
-
var firstIndex = -1;
|
|
672
|
-
var endIndex = -1;
|
|
673
|
-
|
|
674
|
-
if (startIndex < 0 || startIndex >= dataRows.length) {
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
for (var i = 0; i < dataRows.length; i++) {
|
|
679
|
-
|
|
680
|
-
if (
|
|
681
|
-
(
|
|
682
|
-
scrollDown &&
|
|
683
|
-
i >= startIndex &&
|
|
684
|
-
i < startIndex + this.perPage) ||
|
|
685
|
-
(
|
|
686
|
-
!scrollDown &&
|
|
687
|
-
i <= startIndex &&
|
|
688
|
-
i > startIndex - this.perPage
|
|
689
|
-
)
|
|
690
|
-
) {
|
|
691
|
-
aria.Utils.removeClass(dataRows[i], aria.CSSClass.HIDDEN);
|
|
692
|
-
|
|
693
|
-
if (!reachedTop) {
|
|
694
|
-
this.topIndex = i;
|
|
695
|
-
reachedTop = true;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
if (firstIndex < 0) {
|
|
699
|
-
firstIndex = i;
|
|
700
|
-
}
|
|
701
|
-
endIndex = i;
|
|
702
|
-
}
|
|
703
|
-
else {
|
|
704
|
-
aria.Utils.addClass(dataRows[i], aria.CSSClass.HIDDEN);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
this.onPaginationChange(firstIndex, endIndex);
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* @desc
|
|
712
|
-
* Throttle restructuring to only happen every 300ms
|
|
713
|
-
*/
|
|
714
|
-
aria.Grid.prototype.checkRestructureGrid = function () {
|
|
715
|
-
if (this.waitingToRestructure) {
|
|
716
|
-
return;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
this.waitingToRestructure = true;
|
|
720
|
-
|
|
721
|
-
setTimeout(this.restructureGrid, 300);
|
|
722
|
-
};
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* @desc
|
|
726
|
-
* Restructure grid based on the size.
|
|
727
|
-
*/
|
|
728
|
-
aria.Grid.prototype.restructureGrid = function () {
|
|
729
|
-
this.waitingToRestructure = false;
|
|
730
|
-
|
|
731
|
-
var gridWidth = this.gridNode.offsetWidth;
|
|
732
|
-
var cells = this.gridNode.querySelectorAll(aria.GridSelector.CELL);
|
|
733
|
-
var currentWidth = 0;
|
|
734
|
-
|
|
735
|
-
var focusedElement = this.gridNode.querySelector(aria.GridSelector.TABBABLE);
|
|
736
|
-
var shouldRefocus = (document.activeElement === focusedElement);
|
|
737
|
-
var focusedIndex = (this.focusedRow * this.grid[0].length + this.focusedCol);
|
|
738
|
-
|
|
739
|
-
var newRow = document.createElement('div');
|
|
740
|
-
newRow.setAttribute('role', 'row');
|
|
741
|
-
this.gridNode.innerHTML = '';
|
|
742
|
-
this.gridNode.append(newRow);
|
|
743
|
-
|
|
744
|
-
cells.forEach(function (cell, index) {
|
|
745
|
-
var cellWidth = cell.offsetWidth;
|
|
746
|
-
|
|
747
|
-
if (currentWidth > 0 && currentWidth >= (gridWidth - cellWidth)) {
|
|
748
|
-
newRow = document.createElement('div');
|
|
749
|
-
newRow.setAttribute('role', 'row');
|
|
750
|
-
this.gridNode.append(newRow);
|
|
751
|
-
currentWidth = 0;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
newRow.append(cell);
|
|
755
|
-
currentWidth += cellWidth;
|
|
756
|
-
});
|
|
757
|
-
|
|
758
|
-
this.setupFocusGrid();
|
|
759
|
-
|
|
760
|
-
this.focusedRow = Math.floor(focusedIndex / this.grid[0].length);
|
|
761
|
-
this.focusedCol = focusedIndex % this.grid[0].length;
|
|
762
|
-
|
|
763
|
-
if (shouldRefocus) {
|
|
764
|
-
this.focusCell(this.focusedRow, this.focusedCol);
|
|
765
|
-
}
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* @desc
|
|
770
|
-
* Get next cell to the right or left (direction) of the focused
|
|
771
|
-
* cell.
|
|
772
|
-
*
|
|
773
|
-
* @param currRow
|
|
774
|
-
* Row index to start searching from
|
|
775
|
-
*
|
|
776
|
-
* @param currCol
|
|
777
|
-
* Column index to start searching from
|
|
778
|
-
*
|
|
779
|
-
* @param directionX
|
|
780
|
-
* X direction for where to check for cells. +1 to check to the right, -1 to
|
|
781
|
-
* check to the left
|
|
782
|
-
*
|
|
783
|
-
* @return
|
|
784
|
-
* Indices of the next cell in the specified direction. Returns the focused
|
|
785
|
-
* cell if none are found.
|
|
786
|
-
*/
|
|
787
|
-
aria.Grid.prototype.getNextCell = function (
|
|
788
|
-
currRow,
|
|
789
|
-
currCol,
|
|
790
|
-
directionX,
|
|
791
|
-
directionY
|
|
792
|
-
) {
|
|
793
|
-
var row = currRow + directionY;
|
|
794
|
-
var col = currCol + directionX;
|
|
795
|
-
var rowCount = this.grid.length;
|
|
796
|
-
var isLeftRight = directionX !== 0;
|
|
797
|
-
|
|
798
|
-
if (!rowCount) {
|
|
799
|
-
return false;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
var colCount = this.grid[0].length;
|
|
803
|
-
|
|
804
|
-
if (this.shouldWrapCols && isLeftRight) {
|
|
805
|
-
if (col < 0) {
|
|
806
|
-
col = colCount - 1;
|
|
807
|
-
row--;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
if (col >= colCount) {
|
|
811
|
-
col = 0;
|
|
812
|
-
row++;
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
if (this.shouldWrapRows && !isLeftRight) {
|
|
817
|
-
if (row < 0) {
|
|
818
|
-
col--;
|
|
819
|
-
row = rowCount - 1;
|
|
820
|
-
if (this.grid[row] && col >= 0 && !this.grid[row][col]) {
|
|
821
|
-
// Sometimes the bottom row is not completely filled in. In this case,
|
|
822
|
-
// jump to the next filled in cell.
|
|
823
|
-
row--;
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
else if (row >= rowCount || !this.grid[row][col]) {
|
|
827
|
-
row = 0;
|
|
828
|
-
col++;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
if (this.isValidCell(row, col)) {
|
|
833
|
-
return {
|
|
834
|
-
row: row,
|
|
835
|
-
col: col
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
else if (this.isValidCell(currRow, currCol)) {
|
|
839
|
-
return {
|
|
840
|
-
row: currRow,
|
|
841
|
-
col: currCol
|
|
842
|
-
};
|
|
843
|
-
}
|
|
844
|
-
else {
|
|
845
|
-
return false;
|
|
846
|
-
}
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
/**
|
|
850
|
-
* @desc
|
|
851
|
-
* Get next visible column to the right or left (direction) of the focused
|
|
852
|
-
* cell.
|
|
853
|
-
*
|
|
854
|
-
* @param direction
|
|
855
|
-
* Direction for where to check for cells. +1 to check to the right, -1 to
|
|
856
|
-
* check to the left
|
|
857
|
-
*
|
|
858
|
-
* @return
|
|
859
|
-
* Indices of the next visible cell in the specified direction. If no visible
|
|
860
|
-
* cells are found, returns false if the current cell is hidden and returns
|
|
861
|
-
* the current cell if it is not hidden.
|
|
862
|
-
*/
|
|
863
|
-
aria.Grid.prototype.getNextVisibleCell = function (directionX, directionY) {
|
|
864
|
-
var nextCell = this.getNextCell(
|
|
865
|
-
this.focusedRow,
|
|
866
|
-
this.focusedCol,
|
|
867
|
-
directionX,
|
|
868
|
-
directionY
|
|
869
|
-
);
|
|
870
|
-
|
|
871
|
-
if (!nextCell) {
|
|
872
|
-
return false;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
var rowCount = this.grid.length;
|
|
876
|
-
var colCount = this.grid[nextCell.row].length;
|
|
877
|
-
|
|
878
|
-
while (this.isHidden(nextCell.row, nextCell.col)) {
|
|
879
|
-
var currRow = nextCell.row;
|
|
880
|
-
var currCol = nextCell.col;
|
|
881
|
-
|
|
882
|
-
nextCell = this.getNextCell(currRow, currCol, directionX, directionY);
|
|
883
|
-
|
|
884
|
-
if (currRow === nextCell.row && currCol === nextCell.col) {
|
|
885
|
-
// There are no more cells to try if getNextCell returns the current cell
|
|
886
|
-
return false;
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
return nextCell;
|
|
891
|
-
};
|
|
892
|
-
|
|
893
|
-
/**
|
|
894
|
-
* @desc
|
|
895
|
-
* Show or hide the cells in the specified column
|
|
896
|
-
*
|
|
897
|
-
* @param columnIndex
|
|
898
|
-
* Index of the column to toggle
|
|
899
|
-
*
|
|
900
|
-
* @param isShown
|
|
901
|
-
* Whether or not to show the column
|
|
902
|
-
*/
|
|
903
|
-
aria.Grid.prototype.toggleColumn = function (columnIndex, isShown) {
|
|
904
|
-
var cellSelector = '[aria-colindex="' + columnIndex + '"]';
|
|
905
|
-
var columnCells = this.gridNode.querySelectorAll(cellSelector);
|
|
906
|
-
|
|
907
|
-
Array.prototype.forEach.call(
|
|
908
|
-
columnCells,
|
|
909
|
-
function (cell) {
|
|
910
|
-
if (isShown) {
|
|
911
|
-
aria.Utils.removeClass(cell, aria.CSSClass.HIDDEN);
|
|
912
|
-
}
|
|
913
|
-
else {
|
|
914
|
-
aria.Utils.addClass(cell, aria.CSSClass.HIDDEN);
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
);
|
|
918
|
-
|
|
919
|
-
if (!isShown && this.focusedCol === (columnIndex - 1)) {
|
|
920
|
-
// If focus was set on the hidden column, shift focus to the right
|
|
921
|
-
var nextCell = this.getNextVisibleCell(1, 0);
|
|
922
|
-
if (nextCell) {
|
|
923
|
-
this.setFocusPointer(nextCell.row, nextCell.col);
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
};
|
|
927
|
-
|
|
928
|
-
/**
|
|
929
|
-
* @desc
|
|
930
|
-
* Find the closest element matching the selector. Only checks parent and
|
|
931
|
-
* direct children.
|
|
932
|
-
*
|
|
933
|
-
* @param element
|
|
934
|
-
* Element to start searching from
|
|
935
|
-
*
|
|
936
|
-
* @param selector
|
|
937
|
-
* Index of the column to toggle
|
|
938
|
-
*/
|
|
939
|
-
aria.Grid.prototype.findClosest = function (element, selector) {
|
|
940
|
-
if (aria.Utils.matches(element, selector)) {
|
|
941
|
-
return element;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
if (aria.Utils.matches(element.parentNode, selector)) {
|
|
945
|
-
return element.parentNode;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
return element.querySelector(selector);
|
|
949
|
-
};
|
|
950
|
-
}
|
|
1
|
+
export function dataGrid(aria) {
|
|
2
|
+
/*
|
|
3
|
+
* This content is licensed according to the W3C Software License at
|
|
4
|
+
* https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
|
|
5
|
+
* Original source:
|
|
6
|
+
* https://www.w3.org/TR/wai-aria-practices-1.1/examples/grid/js/dataGrid.js
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @namespace aria
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @desc
|
|
15
|
+
* Values for aria-sort
|
|
16
|
+
*/
|
|
17
|
+
aria.SortType = {
|
|
18
|
+
ASCENDING: 'ascending',
|
|
19
|
+
DESCENDING: 'descending',
|
|
20
|
+
NONE: 'none'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @desc
|
|
25
|
+
* DOM Selectors to find the grid components
|
|
26
|
+
*/
|
|
27
|
+
aria.GridSelector = {
|
|
28
|
+
ROW: 'tr, [role="row"]',
|
|
29
|
+
CELL: 'th, td, [role="gridcell"]',
|
|
30
|
+
SCROLL_ROW: 'tr:not([data-fixed]), [role="row"]',
|
|
31
|
+
SORT_HEADER: 'th[aria-sort]',
|
|
32
|
+
TABBABLE: '[tabindex="0"]'
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @desc
|
|
37
|
+
* CSS Class names
|
|
38
|
+
*/
|
|
39
|
+
aria.CSSClass = {
|
|
40
|
+
HIDDEN: 'hidden'
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @constructor
|
|
45
|
+
*
|
|
46
|
+
* @desc
|
|
47
|
+
* Grid object representing the state and interactions for a grid widget
|
|
48
|
+
*
|
|
49
|
+
* Assumptions:
|
|
50
|
+
* All focusable cells initially have tabindex="-1"
|
|
51
|
+
* Produces a fully filled in mxn grid (with no holes)
|
|
52
|
+
*
|
|
53
|
+
* @param gridNode
|
|
54
|
+
* The DOM node pointing to the grid
|
|
55
|
+
*/
|
|
56
|
+
aria.Grid = function (gridNode) {
|
|
57
|
+
this.navigationDisabled = false;
|
|
58
|
+
this.gridNode = gridNode;
|
|
59
|
+
this.paginationEnabled = this.gridNode.hasAttribute('data-per-page');
|
|
60
|
+
this.shouldWrapCols = this.gridNode.hasAttribute('data-wrap-cols');
|
|
61
|
+
this.shouldWrapRows = this.gridNode.hasAttribute('data-wrap-rows');
|
|
62
|
+
this.shouldRestructure = this.gridNode.hasAttribute('data-restructure');
|
|
63
|
+
this.topIndex = 0;
|
|
64
|
+
|
|
65
|
+
this.keysIndicator = document.getElementById('arrow-keys-indicator');
|
|
66
|
+
|
|
67
|
+
aria.Utils.bindMethods(this,
|
|
68
|
+
'checkFocusChange', 'checkPageChange', 'checkRestructureGrid',
|
|
69
|
+
'delegateButtonHandler', 'focusClickedCell', 'restructureGrid',
|
|
70
|
+
'showKeysIndicator', 'hideKeysIndicator');
|
|
71
|
+
this.setupFocusGrid();
|
|
72
|
+
this.setFocusPointer(0, 0);
|
|
73
|
+
|
|
74
|
+
if (this.paginationEnabled) {
|
|
75
|
+
this.setupPagination();
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.perPage = this.grid.length;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.registerEvents();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @desc
|
|
86
|
+
* Creates a 2D array of the focusable cells in the grid.
|
|
87
|
+
*/
|
|
88
|
+
aria.Grid.prototype.setupFocusGrid = function () {
|
|
89
|
+
this.grid = [];
|
|
90
|
+
|
|
91
|
+
Array.prototype.forEach.call(
|
|
92
|
+
this.gridNode.querySelectorAll(aria.GridSelector.ROW),
|
|
93
|
+
(function (row) {
|
|
94
|
+
var rowCells = [];
|
|
95
|
+
|
|
96
|
+
Array.prototype.forEach.call(
|
|
97
|
+
row.querySelectorAll(aria.GridSelector.CELL),
|
|
98
|
+
(function (cell) {
|
|
99
|
+
var focusableSelector = '[tabindex]';
|
|
100
|
+
|
|
101
|
+
if (aria.Utils.matches(cell, focusableSelector)) {
|
|
102
|
+
rowCells.push(cell);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
var focusableCell = cell.querySelector(focusableSelector);
|
|
106
|
+
|
|
107
|
+
if (focusableCell) {
|
|
108
|
+
rowCells.push(focusableCell);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}).bind(this)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (rowCells.length) {
|
|
115
|
+
this.grid.push(rowCells);
|
|
116
|
+
}
|
|
117
|
+
}).bind(this)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
if (this.paginationEnabled) {
|
|
121
|
+
this.setupIndices();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @desc
|
|
127
|
+
* If possible, set focus pointer to the cell with the specified coordinates
|
|
128
|
+
*
|
|
129
|
+
* @param row
|
|
130
|
+
* The index of the cell's row
|
|
131
|
+
*
|
|
132
|
+
* @param col
|
|
133
|
+
* The index of the cell's column
|
|
134
|
+
*
|
|
135
|
+
* @returns
|
|
136
|
+
* Returns whether or not the focus could be set on the cell.
|
|
137
|
+
*/
|
|
138
|
+
aria.Grid.prototype.setFocusPointer = function (row, col) {
|
|
139
|
+
if (!this.isValidCell(row, col)) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (this.isHidden(row, col)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!isNaN(this.focusedRow) && !isNaN(this.focusedCol)) {
|
|
148
|
+
this.grid[this.focusedRow][this.focusedCol].setAttribute('tabindex', -1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.grid[row][col]
|
|
152
|
+
.removeEventListener('focus', this.showKeysIndicator);
|
|
153
|
+
this.grid[row][col]
|
|
154
|
+
.removeEventListener('blur', this.hideKeysIndicator);
|
|
155
|
+
|
|
156
|
+
// Disable navigation if focused on an input
|
|
157
|
+
this.navigationDisabled = aria.Utils.matches(this.grid[row][col], 'input');
|
|
158
|
+
|
|
159
|
+
this.grid[row][col].setAttribute('tabindex', 0);
|
|
160
|
+
this.focusedRow = row;
|
|
161
|
+
this.focusedCol = col;
|
|
162
|
+
|
|
163
|
+
this.grid[row][col]
|
|
164
|
+
.addEventListener('focus', this.showKeysIndicator);
|
|
165
|
+
this.grid[row][col]
|
|
166
|
+
.addEventListener('blur', this.hideKeysIndicator);
|
|
167
|
+
|
|
168
|
+
return true;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @param row
|
|
173
|
+
* The index of the cell's row
|
|
174
|
+
*
|
|
175
|
+
* @param col
|
|
176
|
+
* The index of the cell's column
|
|
177
|
+
*
|
|
178
|
+
* @returns
|
|
179
|
+
* Returns whether or not the coordinates are within the grid's boundaries.
|
|
180
|
+
*/
|
|
181
|
+
aria.Grid.prototype.isValidCell = function (row, col) {
|
|
182
|
+
return (
|
|
183
|
+
!isNaN(row) &&
|
|
184
|
+
!isNaN(col) &&
|
|
185
|
+
row >= 0 &&
|
|
186
|
+
col >= 0 &&
|
|
187
|
+
this.grid &&
|
|
188
|
+
this.grid.length &&
|
|
189
|
+
row < this.grid.length &&
|
|
190
|
+
col < this.grid[row].length
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @param row
|
|
196
|
+
* The index of the cell's row
|
|
197
|
+
*
|
|
198
|
+
* @param col
|
|
199
|
+
* The index of the cell's column
|
|
200
|
+
*
|
|
201
|
+
* @returns
|
|
202
|
+
* Returns whether or not the cell has been hidden.
|
|
203
|
+
*/
|
|
204
|
+
aria.Grid.prototype.isHidden = function (row, col) {
|
|
205
|
+
var cell = this.gridNode.querySelectorAll(aria.GridSelector.ROW)[row]
|
|
206
|
+
.querySelectorAll(aria.GridSelector.CELL)[col];
|
|
207
|
+
return aria.Utils.hasClass(cell, aria.CSSClass.HIDDEN);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @desc
|
|
212
|
+
* Clean up grid events
|
|
213
|
+
*/
|
|
214
|
+
aria.Grid.prototype.clearEvents = function () {
|
|
215
|
+
this.gridNode.removeEventListener('keydown', this.checkFocusChange);
|
|
216
|
+
this.gridNode.removeEventListener('keydown', this.delegateButtonHandler);
|
|
217
|
+
this.gridNode.removeEventListener('click', this.focusClickedCell);
|
|
218
|
+
this.gridNode.removeEventListener('click', this.delegateButtonHandler);
|
|
219
|
+
|
|
220
|
+
if (this.paginationEnabled) {
|
|
221
|
+
this.gridNode.removeEventListener('keydown', this.checkPageChange);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (this.shouldRestructure) {
|
|
225
|
+
window.removeEventListener('resize', this.checkRestructureGrid);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
this.grid[this.focusedRow][this.focusedCol]
|
|
229
|
+
.removeEventListener('focus', this.showKeysIndicator);
|
|
230
|
+
this.grid[this.focusedRow][this.focusedCol]
|
|
231
|
+
.removeEventListener('blur', this.hideKeysIndicator);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @desc
|
|
236
|
+
* Register grid events
|
|
237
|
+
*/
|
|
238
|
+
aria.Grid.prototype.registerEvents = function () {
|
|
239
|
+
this.clearEvents();
|
|
240
|
+
|
|
241
|
+
this.gridNode.addEventListener('keydown', this.checkFocusChange);
|
|
242
|
+
this.gridNode.addEventListener('keydown', this.delegateButtonHandler);
|
|
243
|
+
this.gridNode.addEventListener('click', this.focusClickedCell);
|
|
244
|
+
this.gridNode.addEventListener('click', this.delegateButtonHandler);
|
|
245
|
+
|
|
246
|
+
if (this.paginationEnabled) {
|
|
247
|
+
this.gridNode.addEventListener('keydown', this.checkPageChange);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (this.shouldRestructure) {
|
|
251
|
+
window.addEventListener('resize', this.checkRestructureGrid);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @desc
|
|
257
|
+
* Focus on the cell in the specified row and column
|
|
258
|
+
*
|
|
259
|
+
* @param row
|
|
260
|
+
* The index of the cell's row
|
|
261
|
+
*
|
|
262
|
+
* @param col
|
|
263
|
+
* The index of the cell's column
|
|
264
|
+
*/
|
|
265
|
+
aria.Grid.prototype.focusCell = function (row, col) {
|
|
266
|
+
if (this.setFocusPointer(row, col)) {
|
|
267
|
+
this.grid[row][col].focus();
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
aria.Grid.prototype.showKeysIndicator = function () {
|
|
272
|
+
if (this.keysIndicator) {
|
|
273
|
+
aria.Utils.removeClass(this.keysIndicator, 'hidden');
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
aria.Grid.prototype.hideKeysIndicator = function () {
|
|
278
|
+
if (this.keysIndicator &&
|
|
279
|
+
this.grid[this.focusedRow][this.focusedCol].tabIndex === 0) {
|
|
280
|
+
aria.Utils.addClass(this.keysIndicator, 'hidden');
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @desc
|
|
286
|
+
* Triggered on keydown. Checks if an arrow key was pressed, and (if possible)
|
|
287
|
+
* moves focus to the next valid cell in the direction of the arrow key.
|
|
288
|
+
*
|
|
289
|
+
* @param event
|
|
290
|
+
* Keydown event
|
|
291
|
+
*/
|
|
292
|
+
aria.Grid.prototype.checkFocusChange = function (event) {
|
|
293
|
+
if (!event || this.navigationDisabled) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.findFocusedItem(event.target);
|
|
298
|
+
|
|
299
|
+
var key = event.which || event.keyCode;
|
|
300
|
+
var rowCaret = this.focusedRow;
|
|
301
|
+
var colCaret = this.focusedCol;
|
|
302
|
+
var nextCell;
|
|
303
|
+
|
|
304
|
+
switch (key) {
|
|
305
|
+
case aria.KeyCode.UP:
|
|
306
|
+
nextCell = this.getNextVisibleCell(0, -1);
|
|
307
|
+
rowCaret = nextCell.row;
|
|
308
|
+
colCaret = nextCell.col;
|
|
309
|
+
break;
|
|
310
|
+
case aria.KeyCode.DOWN:
|
|
311
|
+
nextCell = this.getNextVisibleCell(0, 1);
|
|
312
|
+
rowCaret = nextCell.row;
|
|
313
|
+
colCaret = nextCell.col;
|
|
314
|
+
break;
|
|
315
|
+
case aria.KeyCode.LEFT:
|
|
316
|
+
nextCell = this.getNextVisibleCell(-1, 0);
|
|
317
|
+
rowCaret = nextCell.row;
|
|
318
|
+
colCaret = nextCell.col;
|
|
319
|
+
break;
|
|
320
|
+
case aria.KeyCode.RIGHT:
|
|
321
|
+
nextCell = this.getNextVisibleCell(1, 0);
|
|
322
|
+
rowCaret = nextCell.row;
|
|
323
|
+
colCaret = nextCell.col;
|
|
324
|
+
break;
|
|
325
|
+
case aria.KeyCode.HOME:
|
|
326
|
+
if (event.ctrlKey) {
|
|
327
|
+
rowCaret = 0;
|
|
328
|
+
}
|
|
329
|
+
colCaret = 0;
|
|
330
|
+
break;
|
|
331
|
+
case aria.KeyCode.END:
|
|
332
|
+
if (event.ctrlKey) {
|
|
333
|
+
rowCaret = this.grid.length - 1;
|
|
334
|
+
}
|
|
335
|
+
colCaret = this.grid[this.focusedRow].length - 1;
|
|
336
|
+
break;
|
|
337
|
+
default:
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (this.paginationEnabled) {
|
|
342
|
+
if (rowCaret < this.topIndex) {
|
|
343
|
+
this.showFromRow(rowCaret, true);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (rowCaret >= this.topIndex + this.perPage) {
|
|
347
|
+
this.showFromRow(rowCaret, false);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.focusCell(rowCaret, colCaret);
|
|
352
|
+
event.preventDefault();
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* @desc
|
|
357
|
+
* Reset focused row and col if it doesn't match focusedRow and focusedCol
|
|
358
|
+
*
|
|
359
|
+
* @param focusedTarget
|
|
360
|
+
* Element that is currently focused by browser
|
|
361
|
+
*/
|
|
362
|
+
aria.Grid.prototype.findFocusedItem = function (focusedTarget) {
|
|
363
|
+
var focusedCell = this.grid[this.focusedRow][this.focusedCol];
|
|
364
|
+
|
|
365
|
+
if (focusedCell === focusedTarget ||
|
|
366
|
+
focusedCell.contains(focusedTarget)) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
for (var i = 0; i < this.grid.length; i++) {
|
|
371
|
+
for (var j = 0; j < this.grid[i].length; j++) {
|
|
372
|
+
if (this.grid[i][j] === focusedTarget ||
|
|
373
|
+
this.grid[i][j].contains(focusedTarget)) {
|
|
374
|
+
this.setFocusPointer(i, j);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @desc
|
|
383
|
+
* Triggered on click. Finds the cell that was clicked on and focuses on it.
|
|
384
|
+
*
|
|
385
|
+
* @param event
|
|
386
|
+
* Keydown event
|
|
387
|
+
*/
|
|
388
|
+
aria.Grid.prototype.focusClickedCell = function (event) {
|
|
389
|
+
var clickedGridCell = this.findClosest(event.target, '[tabindex]');
|
|
390
|
+
|
|
391
|
+
for (var row = 0; row < this.grid.length; row++) {
|
|
392
|
+
for (var col = 0; col < this.grid[row].length; col++) {
|
|
393
|
+
if (this.grid[row][col] === clickedGridCell) {
|
|
394
|
+
this.setFocusPointer(row, col);
|
|
395
|
+
|
|
396
|
+
if (!aria.Utils.matches(clickedGridCell, 'button[aria-haspopup]')) {
|
|
397
|
+
// Don't focus if it's a menu button (focus should be set to menu)
|
|
398
|
+
this.focusCell(row, col);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @desc
|
|
409
|
+
* Triggered on click. Checks if user clicked on a header with aria-sort.
|
|
410
|
+
* If so, it sorts the column based on the aria-sort attribute.
|
|
411
|
+
*
|
|
412
|
+
* @param event
|
|
413
|
+
* Keydown event
|
|
414
|
+
*/
|
|
415
|
+
aria.Grid.prototype.delegateButtonHandler = function (event) {
|
|
416
|
+
var key = event.which || event.keyCode;
|
|
417
|
+
var target = event.target;
|
|
418
|
+
var isClickEvent = (event.type === 'click');
|
|
419
|
+
|
|
420
|
+
if (!target) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (
|
|
425
|
+
target.parentNode &&
|
|
426
|
+
target.parentNode.matches('th[aria-sort]') &&
|
|
427
|
+
(
|
|
428
|
+
isClickEvent ||
|
|
429
|
+
key === aria.KeyCode.SPACE ||
|
|
430
|
+
key === aria.KeyCode.RETURN
|
|
431
|
+
)
|
|
432
|
+
) {
|
|
433
|
+
event.preventDefault();
|
|
434
|
+
this.handleSort(target.parentNode);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (
|
|
438
|
+
aria.Utils.matches(target, '.editable-text, .edit-text-button') &&
|
|
439
|
+
(
|
|
440
|
+
isClickEvent ||
|
|
441
|
+
key === aria.KeyCode.RETURN
|
|
442
|
+
)
|
|
443
|
+
) {
|
|
444
|
+
event.preventDefault();
|
|
445
|
+
this.toggleEditMode(
|
|
446
|
+
this.findClosest(target, '.editable-text'),
|
|
447
|
+
true,
|
|
448
|
+
true
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (
|
|
453
|
+
aria.Utils.matches(target, '.edit-text-input') &&
|
|
454
|
+
(
|
|
455
|
+
key === aria.KeyCode.RETURN ||
|
|
456
|
+
key === aria.KeyCode.ESC
|
|
457
|
+
)
|
|
458
|
+
) {
|
|
459
|
+
event.preventDefault();
|
|
460
|
+
this.toggleEditMode(
|
|
461
|
+
this.findClosest(target, '.editable-text'),
|
|
462
|
+
false,
|
|
463
|
+
key === aria.KeyCode.RETURN
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* @desc
|
|
470
|
+
* Toggles the mode of an editable cell between displaying the edit button
|
|
471
|
+
* and displaying the editable input.
|
|
472
|
+
*
|
|
473
|
+
* @param editCell
|
|
474
|
+
* Cell to toggle
|
|
475
|
+
*
|
|
476
|
+
* @param toggleOn
|
|
477
|
+
* Whether to show or hide edit input
|
|
478
|
+
*
|
|
479
|
+
* @param updateText
|
|
480
|
+
* Whether or not to update the button text with the input text
|
|
481
|
+
*/
|
|
482
|
+
aria.Grid.prototype.toggleEditMode = function (editCell, toggleOn, updateText) {
|
|
483
|
+
var onClassName = toggleOn ? 'edit-text-input' : 'edit-text-button';
|
|
484
|
+
var offClassName = toggleOn ? 'edit-text-button' : 'edit-text-input';
|
|
485
|
+
var onNode = editCell.querySelector('.' + onClassName);
|
|
486
|
+
var offNode = editCell.querySelector('.' + offClassName);
|
|
487
|
+
|
|
488
|
+
if (toggleOn) {
|
|
489
|
+
onNode.value = offNode.innerText;
|
|
490
|
+
}
|
|
491
|
+
else if (updateText) {
|
|
492
|
+
onNode.innerText = offNode.value;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
aria.Utils.addClass(offNode, aria.CSSClass.HIDDEN);
|
|
496
|
+
aria.Utils.removeClass(onNode, aria.CSSClass.HIDDEN);
|
|
497
|
+
offNode.setAttribute('tabindex', -1);
|
|
498
|
+
onNode.setAttribute('tabindex', 0);
|
|
499
|
+
onNode.focus();
|
|
500
|
+
this.grid[this.focusedRow][this.focusedCol] = onNode;
|
|
501
|
+
this.navigationDisabled = toggleOn;
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* @desc
|
|
506
|
+
* Sorts the column below the header node, based on the aria-sort attribute.
|
|
507
|
+
* aria-sort="none" => aria-sort="ascending"
|
|
508
|
+
* aria-sort="ascending" => aria-sort="descending"
|
|
509
|
+
* All other headers with aria-sort are reset to "none"
|
|
510
|
+
*
|
|
511
|
+
* Note: This implementation assumes that there is no pagination on the grid.
|
|
512
|
+
*
|
|
513
|
+
* @param headerNode
|
|
514
|
+
* Header DOM node
|
|
515
|
+
*/
|
|
516
|
+
aria.Grid.prototype.handleSort = function (headerNode) {
|
|
517
|
+
var columnIndex = headerNode.cellIndex;
|
|
518
|
+
var sortType = headerNode.getAttribute('aria-sort');
|
|
519
|
+
|
|
520
|
+
if (sortType === aria.SortType.ASCENDING) {
|
|
521
|
+
sortType = aria.SortType.DESCENDING;
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
sortType = aria.SortType.ASCENDING;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
var comparator = function (row1, row2) {
|
|
528
|
+
if(row1.children[columnIndex].classList.contains('align-top') || row2.children[columnIndex].classList.contains('align-top')) {
|
|
529
|
+
return
|
|
530
|
+
}
|
|
531
|
+
var row1Text = row1.children[columnIndex].innerText;
|
|
532
|
+
var row2Text = row2.children[columnIndex].innerText;
|
|
533
|
+
var row1Value = parseInt(row1Text) ? parseInt(row1Text.replace(/[^0-9\.]+/g, '')) : row1Text
|
|
534
|
+
var row2Value = parseInt(row2Text) ? parseInt(row2Text.replace(/[^0-9\.]+/g, '')) : row2Text
|
|
535
|
+
|
|
536
|
+
var orderValue = parseInt(row1Text) ? 'numbers' : 'strings'
|
|
537
|
+
|
|
538
|
+
if (sortType === aria.SortType.ASCENDING && orderValue === 'numbers') {
|
|
539
|
+
return row1Value - row2Value;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (sortType === aria.SortType.DESCENDING && orderValue === 'numbers') {
|
|
543
|
+
return row2Value - row1Value;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (sortType === aria.SortType.ASCENDING && orderValue === 'strings') {
|
|
547
|
+
return row1Value.toString().localeCompare(row2Value);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (sortType === aria.SortType.DESCENDING && orderValue === 'strings') {
|
|
551
|
+
return row2Value.toString().localeCompare(row1Value);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
this.sortRows(comparator);
|
|
557
|
+
this.setupFocusGrid();
|
|
558
|
+
|
|
559
|
+
Array.prototype.forEach.call(
|
|
560
|
+
this.gridNode.querySelectorAll(aria.GridSelector.SORT_HEADER),
|
|
561
|
+
function (headerCell) {
|
|
562
|
+
headerCell.setAttribute('aria-sort', aria.SortType.NONE);
|
|
563
|
+
}
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
headerNode.setAttribute('aria-sort', sortType);
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* @desc
|
|
571
|
+
* Sorts the grid's rows according to the specified compareFn
|
|
572
|
+
*
|
|
573
|
+
* @param compareFn
|
|
574
|
+
* Comparison function to sort the rows
|
|
575
|
+
*/
|
|
576
|
+
aria.Grid.prototype.sortRows = function (compareFn) {
|
|
577
|
+
var rows = this.gridNode.querySelectorAll("tbody tr");
|
|
578
|
+
var rowWrapper = this.gridNode.querySelector('tbody');
|
|
579
|
+
var dataRows = Array.prototype.slice.call(rows, 1);
|
|
580
|
+
|
|
581
|
+
dataRows.sort(compareFn);
|
|
582
|
+
|
|
583
|
+
dataRows.forEach((function (row) {
|
|
584
|
+
rowWrapper.appendChild(row);
|
|
585
|
+
}).bind(this));
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* @desc
|
|
590
|
+
* Adds aria-rowindex and aria-colindex to the cells in the grid
|
|
591
|
+
*/
|
|
592
|
+
aria.Grid.prototype.setupIndices = function () {
|
|
593
|
+
var rows = this.gridNode.querySelectorAll(aria.GridSelector.ROW);
|
|
594
|
+
|
|
595
|
+
for (var row = 0; row < rows.length; row++) {
|
|
596
|
+
var cols = rows[row].querySelectorAll(aria.GridSelector.CELL);
|
|
597
|
+
rows[row].setAttribute('aria-rowindex', row + 1);
|
|
598
|
+
|
|
599
|
+
for (var col = 0; col < cols.length; col++) {
|
|
600
|
+
cols[col].setAttribute('aria-colindex', col + 1);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* @desc
|
|
608
|
+
* Determines the per page attribute of the grid, and shows/hides rows
|
|
609
|
+
* accordingly.
|
|
610
|
+
*/
|
|
611
|
+
aria.Grid.prototype.setupPagination = function () {
|
|
612
|
+
this.onPaginationChange = this.onPaginationChange || function () {};
|
|
613
|
+
this.perPage = parseInt(this.gridNode.getAttribute('data-per-page'));
|
|
614
|
+
this.showFromRow(0, true);
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
aria.Grid.prototype.setPaginationChangeHandler = function (onPaginationChange) {
|
|
618
|
+
this.onPaginationChange = onPaginationChange;
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @desc
|
|
623
|
+
* Check if page up or page down was pressed, and show the next page if so.
|
|
624
|
+
*
|
|
625
|
+
* @param event
|
|
626
|
+
* Keydown event
|
|
627
|
+
*/
|
|
628
|
+
aria.Grid.prototype.checkPageChange = function (event) {
|
|
629
|
+
if (!event) {
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
var key = event.which || event.keyCode;
|
|
634
|
+
|
|
635
|
+
if (key === aria.KeyCode.PAGE_UP) {
|
|
636
|
+
event.preventDefault();
|
|
637
|
+
this.movePageUp();
|
|
638
|
+
}
|
|
639
|
+
else if (key === aria.KeyCode.PAGE_DOWN) {
|
|
640
|
+
event.preventDefault();
|
|
641
|
+
this.movePageDown();
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
aria.Grid.prototype.movePageUp = function () {
|
|
646
|
+
var startIndex = Math.max(this.perPage - 1, this.topIndex - 1);
|
|
647
|
+
this.showFromRow(startIndex, false);
|
|
648
|
+
this.focusCell(startIndex, this.focusedCol);
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
aria.Grid.prototype.movePageDown = function () {
|
|
652
|
+
var startIndex = this.topIndex + this.perPage;
|
|
653
|
+
this.showFromRow(startIndex, true);
|
|
654
|
+
this.focusCell(startIndex, this.focusedCol);
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* @desc
|
|
659
|
+
* Scroll the specified row into view in the specified direction
|
|
660
|
+
*
|
|
661
|
+
* @param startIndex
|
|
662
|
+
* Row index to use as the start index
|
|
663
|
+
*
|
|
664
|
+
* @param scrollDown
|
|
665
|
+
* Whether to scroll the new page above or below the row index
|
|
666
|
+
*/
|
|
667
|
+
aria.Grid.prototype.showFromRow = function (startIndex, scrollDown) {
|
|
668
|
+
var dataRows =
|
|
669
|
+
this.gridNode.querySelectorAll(aria.GridSelector.SCROLL_ROW);
|
|
670
|
+
var reachedTop = false;
|
|
671
|
+
var firstIndex = -1;
|
|
672
|
+
var endIndex = -1;
|
|
673
|
+
|
|
674
|
+
if (startIndex < 0 || startIndex >= dataRows.length) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
for (var i = 0; i < dataRows.length; i++) {
|
|
679
|
+
|
|
680
|
+
if (
|
|
681
|
+
(
|
|
682
|
+
scrollDown &&
|
|
683
|
+
i >= startIndex &&
|
|
684
|
+
i < startIndex + this.perPage) ||
|
|
685
|
+
(
|
|
686
|
+
!scrollDown &&
|
|
687
|
+
i <= startIndex &&
|
|
688
|
+
i > startIndex - this.perPage
|
|
689
|
+
)
|
|
690
|
+
) {
|
|
691
|
+
aria.Utils.removeClass(dataRows[i], aria.CSSClass.HIDDEN);
|
|
692
|
+
|
|
693
|
+
if (!reachedTop) {
|
|
694
|
+
this.topIndex = i;
|
|
695
|
+
reachedTop = true;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if (firstIndex < 0) {
|
|
699
|
+
firstIndex = i;
|
|
700
|
+
}
|
|
701
|
+
endIndex = i;
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
aria.Utils.addClass(dataRows[i], aria.CSSClass.HIDDEN);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
this.onPaginationChange(firstIndex, endIndex);
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* @desc
|
|
712
|
+
* Throttle restructuring to only happen every 300ms
|
|
713
|
+
*/
|
|
714
|
+
aria.Grid.prototype.checkRestructureGrid = function () {
|
|
715
|
+
if (this.waitingToRestructure) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
this.waitingToRestructure = true;
|
|
720
|
+
|
|
721
|
+
setTimeout(this.restructureGrid, 300);
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* @desc
|
|
726
|
+
* Restructure grid based on the size.
|
|
727
|
+
*/
|
|
728
|
+
aria.Grid.prototype.restructureGrid = function () {
|
|
729
|
+
this.waitingToRestructure = false;
|
|
730
|
+
|
|
731
|
+
var gridWidth = this.gridNode.offsetWidth;
|
|
732
|
+
var cells = this.gridNode.querySelectorAll(aria.GridSelector.CELL);
|
|
733
|
+
var currentWidth = 0;
|
|
734
|
+
|
|
735
|
+
var focusedElement = this.gridNode.querySelector(aria.GridSelector.TABBABLE);
|
|
736
|
+
var shouldRefocus = (document.activeElement === focusedElement);
|
|
737
|
+
var focusedIndex = (this.focusedRow * this.grid[0].length + this.focusedCol);
|
|
738
|
+
|
|
739
|
+
var newRow = document.createElement('div');
|
|
740
|
+
newRow.setAttribute('role', 'row');
|
|
741
|
+
this.gridNode.innerHTML = '';
|
|
742
|
+
this.gridNode.append(newRow);
|
|
743
|
+
|
|
744
|
+
cells.forEach(function (cell, index) {
|
|
745
|
+
var cellWidth = cell.offsetWidth;
|
|
746
|
+
|
|
747
|
+
if (currentWidth > 0 && currentWidth >= (gridWidth - cellWidth)) {
|
|
748
|
+
newRow = document.createElement('div');
|
|
749
|
+
newRow.setAttribute('role', 'row');
|
|
750
|
+
this.gridNode.append(newRow);
|
|
751
|
+
currentWidth = 0;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
newRow.append(cell);
|
|
755
|
+
currentWidth += cellWidth;
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
this.setupFocusGrid();
|
|
759
|
+
|
|
760
|
+
this.focusedRow = Math.floor(focusedIndex / this.grid[0].length);
|
|
761
|
+
this.focusedCol = focusedIndex % this.grid[0].length;
|
|
762
|
+
|
|
763
|
+
if (shouldRefocus) {
|
|
764
|
+
this.focusCell(this.focusedRow, this.focusedCol);
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* @desc
|
|
770
|
+
* Get next cell to the right or left (direction) of the focused
|
|
771
|
+
* cell.
|
|
772
|
+
*
|
|
773
|
+
* @param currRow
|
|
774
|
+
* Row index to start searching from
|
|
775
|
+
*
|
|
776
|
+
* @param currCol
|
|
777
|
+
* Column index to start searching from
|
|
778
|
+
*
|
|
779
|
+
* @param directionX
|
|
780
|
+
* X direction for where to check for cells. +1 to check to the right, -1 to
|
|
781
|
+
* check to the left
|
|
782
|
+
*
|
|
783
|
+
* @return
|
|
784
|
+
* Indices of the next cell in the specified direction. Returns the focused
|
|
785
|
+
* cell if none are found.
|
|
786
|
+
*/
|
|
787
|
+
aria.Grid.prototype.getNextCell = function (
|
|
788
|
+
currRow,
|
|
789
|
+
currCol,
|
|
790
|
+
directionX,
|
|
791
|
+
directionY
|
|
792
|
+
) {
|
|
793
|
+
var row = currRow + directionY;
|
|
794
|
+
var col = currCol + directionX;
|
|
795
|
+
var rowCount = this.grid.length;
|
|
796
|
+
var isLeftRight = directionX !== 0;
|
|
797
|
+
|
|
798
|
+
if (!rowCount) {
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
var colCount = this.grid[0].length;
|
|
803
|
+
|
|
804
|
+
if (this.shouldWrapCols && isLeftRight) {
|
|
805
|
+
if (col < 0) {
|
|
806
|
+
col = colCount - 1;
|
|
807
|
+
row--;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (col >= colCount) {
|
|
811
|
+
col = 0;
|
|
812
|
+
row++;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
if (this.shouldWrapRows && !isLeftRight) {
|
|
817
|
+
if (row < 0) {
|
|
818
|
+
col--;
|
|
819
|
+
row = rowCount - 1;
|
|
820
|
+
if (this.grid[row] && col >= 0 && !this.grid[row][col]) {
|
|
821
|
+
// Sometimes the bottom row is not completely filled in. In this case,
|
|
822
|
+
// jump to the next filled in cell.
|
|
823
|
+
row--;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
else if (row >= rowCount || !this.grid[row][col]) {
|
|
827
|
+
row = 0;
|
|
828
|
+
col++;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (this.isValidCell(row, col)) {
|
|
833
|
+
return {
|
|
834
|
+
row: row,
|
|
835
|
+
col: col
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
else if (this.isValidCell(currRow, currCol)) {
|
|
839
|
+
return {
|
|
840
|
+
row: currRow,
|
|
841
|
+
col: currCol
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
return false;
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* @desc
|
|
851
|
+
* Get next visible column to the right or left (direction) of the focused
|
|
852
|
+
* cell.
|
|
853
|
+
*
|
|
854
|
+
* @param direction
|
|
855
|
+
* Direction for where to check for cells. +1 to check to the right, -1 to
|
|
856
|
+
* check to the left
|
|
857
|
+
*
|
|
858
|
+
* @return
|
|
859
|
+
* Indices of the next visible cell in the specified direction. If no visible
|
|
860
|
+
* cells are found, returns false if the current cell is hidden and returns
|
|
861
|
+
* the current cell if it is not hidden.
|
|
862
|
+
*/
|
|
863
|
+
aria.Grid.prototype.getNextVisibleCell = function (directionX, directionY) {
|
|
864
|
+
var nextCell = this.getNextCell(
|
|
865
|
+
this.focusedRow,
|
|
866
|
+
this.focusedCol,
|
|
867
|
+
directionX,
|
|
868
|
+
directionY
|
|
869
|
+
);
|
|
870
|
+
|
|
871
|
+
if (!nextCell) {
|
|
872
|
+
return false;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
var rowCount = this.grid.length;
|
|
876
|
+
var colCount = this.grid[nextCell.row].length;
|
|
877
|
+
|
|
878
|
+
while (this.isHidden(nextCell.row, nextCell.col)) {
|
|
879
|
+
var currRow = nextCell.row;
|
|
880
|
+
var currCol = nextCell.col;
|
|
881
|
+
|
|
882
|
+
nextCell = this.getNextCell(currRow, currCol, directionX, directionY);
|
|
883
|
+
|
|
884
|
+
if (currRow === nextCell.row && currCol === nextCell.col) {
|
|
885
|
+
// There are no more cells to try if getNextCell returns the current cell
|
|
886
|
+
return false;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
return nextCell;
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* @desc
|
|
895
|
+
* Show or hide the cells in the specified column
|
|
896
|
+
*
|
|
897
|
+
* @param columnIndex
|
|
898
|
+
* Index of the column to toggle
|
|
899
|
+
*
|
|
900
|
+
* @param isShown
|
|
901
|
+
* Whether or not to show the column
|
|
902
|
+
*/
|
|
903
|
+
aria.Grid.prototype.toggleColumn = function (columnIndex, isShown) {
|
|
904
|
+
var cellSelector = '[aria-colindex="' + columnIndex + '"]';
|
|
905
|
+
var columnCells = this.gridNode.querySelectorAll(cellSelector);
|
|
906
|
+
|
|
907
|
+
Array.prototype.forEach.call(
|
|
908
|
+
columnCells,
|
|
909
|
+
function (cell) {
|
|
910
|
+
if (isShown) {
|
|
911
|
+
aria.Utils.removeClass(cell, aria.CSSClass.HIDDEN);
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
aria.Utils.addClass(cell, aria.CSSClass.HIDDEN);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
|
|
919
|
+
if (!isShown && this.focusedCol === (columnIndex - 1)) {
|
|
920
|
+
// If focus was set on the hidden column, shift focus to the right
|
|
921
|
+
var nextCell = this.getNextVisibleCell(1, 0);
|
|
922
|
+
if (nextCell) {
|
|
923
|
+
this.setFocusPointer(nextCell.row, nextCell.col);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* @desc
|
|
930
|
+
* Find the closest element matching the selector. Only checks parent and
|
|
931
|
+
* direct children.
|
|
932
|
+
*
|
|
933
|
+
* @param element
|
|
934
|
+
* Element to start searching from
|
|
935
|
+
*
|
|
936
|
+
* @param selector
|
|
937
|
+
* Index of the column to toggle
|
|
938
|
+
*/
|
|
939
|
+
aria.Grid.prototype.findClosest = function (element, selector) {
|
|
940
|
+
if (aria.Utils.matches(element, selector)) {
|
|
941
|
+
return element;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
if (aria.Utils.matches(element.parentNode, selector)) {
|
|
945
|
+
return element.parentNode;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return element.querySelector(selector);
|
|
949
|
+
};
|
|
950
|
+
}
|