@shortfuse/materialdesignweb 0.2.0 → 0.5.0

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.
Files changed (416) hide show
  1. package/.browserslistrc +2 -1
  2. package/.eslintrc.json +188 -30
  3. package/.stylelintrc.json +643 -2
  4. package/.vscode/launch.json +20 -5
  5. package/.vscode/settings.json +3 -0
  6. package/CHANGELOG.md +36 -0
  7. package/README.md +82 -2
  8. package/adapters/datatable/column.js +176 -0
  9. package/adapters/datatable/index.js +253 -437
  10. package/adapters/dom/index.js +586 -0
  11. package/adapters/list/index.js +36 -113
  12. package/adapters/search/index.js +153 -180
  13. package/components/appbar/_spec.scss +165 -0
  14. package/components/appbar/_theme.scss +0 -0
  15. package/components/appbar/index.scss +2 -0
  16. package/components/banner/_spec.scss +83 -0
  17. package/components/banner/_theme.scss +0 -0
  18. package/components/banner/index.scss +2 -0
  19. package/components/bottomnav/README.md +4 -4
  20. package/components/bottomnav/_spec.scss +149 -0
  21. package/components/bottomnav/_theme.scss +0 -0
  22. package/components/bottomnav/index.js +100 -120
  23. package/components/bottomnav/index.scss +2 -0
  24. package/components/bottomnav/item.js +88 -0
  25. package/components/button/README.md +16 -22
  26. package/components/button/_spec.scss +162 -0
  27. package/components/button/_theme.scss +42 -0
  28. package/components/button/index.eta +32 -0
  29. package/components/button/index.js +37 -48
  30. package/components/button/index.pug +18 -0
  31. package/components/button/index.scss +2 -0
  32. package/components/card/_spec.scss +241 -0
  33. package/components/card/_theme.scss +0 -0
  34. package/components/card/index.scss +2 -0
  35. package/components/chip/_spec.scss +111 -0
  36. package/components/chip/_theme.scss +105 -0
  37. package/components/chip/index.js +23 -0
  38. package/components/chip/index.scss +2 -0
  39. package/components/chip/item.js +20 -0
  40. package/components/datatable/_spec.scss +225 -0
  41. package/components/datatable/_theme.scss +128 -0
  42. package/components/datatable/cell.js +44 -0
  43. package/components/datatable/columnheader.js +46 -0
  44. package/components/datatable/index.js +339 -443
  45. package/components/datatable/index.scss +2 -0
  46. package/components/datatable/row.js +48 -0
  47. package/components/datatable/rowheader.js +18 -0
  48. package/components/dialog/_spec.scss +203 -0
  49. package/components/dialog/_theme.scss +7 -0
  50. package/components/dialog/index.js +512 -437
  51. package/components/dialog/index.scss +2 -0
  52. package/components/divider/_spec.scss +11 -0
  53. package/components/divider/_theme.scss +0 -0
  54. package/components/divider/index.scss +2 -0
  55. package/components/elevation/_spec.scss +9 -0
  56. package/components/elevation/_theme.scss +0 -0
  57. package/components/elevation/index.scss +2 -0
  58. package/components/fab/{style.scss → _spec.scss} +104 -79
  59. package/components/fab/_theme.scss +0 -0
  60. package/components/fab/index.js +85 -79
  61. package/components/fab/index.scss +2 -0
  62. package/components/grid/_spec.scss +169 -0
  63. package/components/grid/_theme.scss +0 -0
  64. package/components/grid/index.scss +2 -0
  65. package/components/layout/_mixins.scss +11 -0
  66. package/components/layout/_spec.scss +916 -0
  67. package/components/layout/_theme.scss +19 -0
  68. package/components/layout/index.js +454 -0
  69. package/components/layout/index.scss +2 -0
  70. package/components/list/_spec.scss +363 -0
  71. package/components/list/_theme.scss +102 -0
  72. package/components/list/content.js +106 -0
  73. package/components/list/index.js +234 -79
  74. package/components/list/index.scss +2 -0
  75. package/components/list/item.js +167 -0
  76. package/components/list/secondary.js +45 -0
  77. package/components/menu/_spec.scss +329 -0
  78. package/components/menu/_theme.scss +0 -0
  79. package/components/menu/index.js +636 -651
  80. package/components/menu/index.scss +2 -0
  81. package/components/menu/item.js +231 -0
  82. package/components/progress/_spec.scss +156 -0
  83. package/components/progress/_theme.scss +0 -0
  84. package/components/progress/index.js +29 -13
  85. package/components/progress/index.scss +2 -0
  86. package/components/selection/_spec.scss +376 -0
  87. package/components/selection/_theme.scss +134 -0
  88. package/components/selection/index.eta +60 -0
  89. package/components/selection/index.js +70 -0
  90. package/components/selection/index.pug +30 -0
  91. package/components/selection/index.scss +2 -0
  92. package/components/selection/input.js +54 -0
  93. package/components/selection/radiogroup.js +40 -0
  94. package/components/slider/{style.scss → _spec.scss} +31 -34
  95. package/components/slider/_theme.scss +0 -0
  96. package/components/slider/index.scss +2 -0
  97. package/components/snackbar/_spec.scss +150 -0
  98. package/components/snackbar/_theme.scss +0 -0
  99. package/components/snackbar/index.js +293 -206
  100. package/components/snackbar/index.scss +2 -0
  101. package/components/tab/_spec.scss +220 -0
  102. package/components/tab/_theme.scss +0 -0
  103. package/components/tab/content.js +210 -0
  104. package/components/tab/index.js +229 -213
  105. package/components/tab/index.scss +2 -0
  106. package/components/tab/item.js +88 -0
  107. package/components/tab/list.js +196 -0
  108. package/components/tab/panel.js +54 -0
  109. package/components/textfield/README.md +4 -4
  110. package/components/textfield/_spec.scss +763 -0
  111. package/components/textfield/_theme.scss +264 -0
  112. package/components/textfield/index.eta +74 -0
  113. package/components/textfield/index.js +132 -138
  114. package/components/textfield/index.pug +30 -0
  115. package/components/textfield/index.scss +2 -0
  116. package/components/tooltip/_spec.scss +185 -0
  117. package/components/tooltip/_theme.scss +0 -0
  118. package/components/tooltip/index.scss +2 -0
  119. package/components/type/_spec.scss +227 -0
  120. package/components/type/_theme.scss +0 -0
  121. package/components/type/index.scss +2 -0
  122. package/core/_breakpoint.scss +189 -0
  123. package/core/_elevation.scss +78 -0
  124. package/core/_length.scss +8 -0
  125. package/core/_motion.scss +31 -0
  126. package/core/_platform.scss +12 -0
  127. package/core/_type.scss +128 -0
  128. package/core/aria/attributes.js +141 -0
  129. package/core/aria/button.js +49 -0
  130. package/core/aria/keyboard.js +92 -0
  131. package/core/aria/rovingtabindex.js +175 -0
  132. package/core/aria/tab.js +59 -0
  133. package/core/document/index.js +39 -0
  134. package/core/dom.js +180 -0
  135. package/core/overlay/_spec.scss +28 -0
  136. package/core/overlay/_theme.scss +147 -0
  137. package/core/overlay/index.js +95 -0
  138. package/core/overlay/index.scss +2 -0
  139. package/core/ripple/_spec.scss +196 -0
  140. package/core/ripple/_theme.scss +20 -0
  141. package/core/ripple/index.js +286 -0
  142. package/core/ripple/index.scss +2 -0
  143. package/core/theme/_aliases.scss +15 -0
  144. package/core/theme/_config.scss +8 -0
  145. package/core/theme/_functions.scss +22 -0
  146. package/{components/theming/palettes.scss → core/theme/_palettes.scss} +173 -151
  147. package/core/theme/_spec.scss +0 -0
  148. package/core/theme/_theme.scss +268 -0
  149. package/core/theme/index.js +50 -0
  150. package/core/theme/index.scss +4 -0
  151. package/core/throttler.js +42 -0
  152. package/core/transition/index.js +465 -0
  153. package/docs/_flex.scss +28 -0
  154. package/docs/_menuoptions.js +183 -0
  155. package/docs/_partials/_androidnavbar.eta +5 -0
  156. package/docs/_partials/_androidstatusbar.eta +13 -0
  157. package/docs/_partials/_appbar.eta +27 -0
  158. package/docs/_partials/_buttontest.eta +31 -0
  159. package/docs/_partials/_header.eta +146 -0
  160. package/docs/_partials/_navlistitem.eta +16 -0
  161. package/docs/_partials/_target.eta +1 -0
  162. package/docs/_sample-utils.js +88 -0
  163. package/docs/{src/storage.js → _storage.js} +0 -0
  164. package/docs/docs.scss +331 -0
  165. package/docs/framework.scss +26 -0
  166. package/docs/index.eta +12 -0
  167. package/docs/index.js +7 -0
  168. package/docs/pages/appbar.eta +108 -0
  169. package/docs/pages/appbar.js +0 -0
  170. package/docs/pages/bottomnav.eta +188 -0
  171. package/docs/pages/bottomnav.js +118 -0
  172. package/docs/pages/button.eta +124 -0
  173. package/docs/pages/button.js +224 -0
  174. package/docs/pages/card.eta +90 -0
  175. package/docs/pages/card.js +175 -0
  176. package/docs/pages/chip.eta +122 -0
  177. package/docs/pages/chip.js +80 -0
  178. package/docs/pages/color.eta +143 -0
  179. package/docs/pages/color.js +261 -0
  180. package/docs/pages/datatable.eta +323 -0
  181. package/docs/pages/datatable.js +160 -0
  182. package/docs/pages/dialog.eta +184 -0
  183. package/docs/{src/components → pages}/dialog.js +35 -48
  184. package/docs/pages/dom.eta +26 -0
  185. package/docs/pages/dom.js +140 -0
  186. package/docs/pages/elevation.eta +35 -0
  187. package/docs/pages/elevation.js +0 -0
  188. package/docs/pages/fab.eta +99 -0
  189. package/docs/{src/components → pages}/fab.js +6 -13
  190. package/docs/pages/grid.eta +135 -0
  191. package/docs/pages/grid.js +128 -0
  192. package/docs/pages/layout.eta +8 -0
  193. package/docs/pages/layout.js +0 -0
  194. package/docs/pages/list.eta +465 -0
  195. package/docs/pages/list.js +8 -0
  196. package/docs/pages/menu.eta +274 -0
  197. package/docs/{src/components → pages}/menu.js +26 -42
  198. package/docs/pages/overlay.eta +69 -0
  199. package/docs/pages/overlay.js +3 -0
  200. package/docs/pages/progress.eta +23 -0
  201. package/docs/{src/components → pages}/progress.js +2 -4
  202. package/docs/pages/ripple.eta +27 -0
  203. package/docs/pages/ripple.js +3 -0
  204. package/docs/pages/search.eta +242 -0
  205. package/docs/pages/search.js +226 -0
  206. package/docs/pages/selection.eta +107 -0
  207. package/docs/pages/selection.js +12 -0
  208. package/docs/pages/slider.eta +23 -0
  209. package/docs/pages/slider.js +0 -0
  210. package/docs/pages/snackbar.eta +83 -0
  211. package/docs/{src/components → pages}/snackbar.js +31 -36
  212. package/docs/pages/tab.eta +407 -0
  213. package/docs/pages/tab.js +152 -0
  214. package/docs/pages/textfield.eta +487 -0
  215. package/docs/{src/components → pages}/textfield.js +41 -45
  216. package/docs/pages/tooltip.eta +92 -0
  217. package/docs/pages/tooltip.js +0 -0
  218. package/docs/pages/transition.eta +117 -0
  219. package/docs/pages/transition.js +52 -0
  220. package/docs/pages/type.eta +31 -0
  221. package/docs/pages/type.js +0 -0
  222. package/docs/postrender.js +41 -0
  223. package/docs/prerender.js +16 -0
  224. package/docs/pwa/_dialogs.eta +143 -0
  225. package/docs/pwa/_menus.eta +16 -0
  226. package/docs/pwa/pwa-prerender.js +3 -0
  227. package/docs/pwa/pwa.eta +478 -0
  228. package/docs/pwa/pwa.js +298 -0
  229. package/docs/pwa/pwa.scss +31 -0
  230. package/docs/themes/theme-colored.scss +15 -0
  231. package/docs/themes/theme-default.scss +3 -0
  232. package/index.scss +27 -0
  233. package/jsconfig.json +8 -2
  234. package/package.json +54 -27
  235. package/scripts/deploy-docs.sh +9 -0
  236. package/templates/index.eta +2 -0
  237. package/templates/index.pug +3 -0
  238. package/tsconfig.json +16 -0
  239. package/utils/function.js +3 -0
  240. package/webpack.config.js +224 -68
  241. package/_index.scss +0 -4
  242. package/components/all-components.scss +0 -21
  243. package/components/bottomnav/style.scss +0 -190
  244. package/components/bottomnav/theming.scss +0 -76
  245. package/components/button/style.scss +0 -315
  246. package/components/button/theming.scss +0 -134
  247. package/components/card/style.scss +0 -175
  248. package/components/card/theming.scss +0 -43
  249. package/components/common/dom.js +0 -51
  250. package/components/common/functions.scss +0 -174
  251. package/components/common/mixins.scss +0 -122
  252. package/components/common/motion.scss +0 -36
  253. package/components/common/type.scss +0 -104
  254. package/components/common/variables.scss +0 -46
  255. package/components/datatable/style.scss +0 -257
  256. package/components/datatable/theming.scss +0 -119
  257. package/components/dialog/style.scss +0 -159
  258. package/components/dialog/theming.scss +0 -29
  259. package/components/divider/style.scss +0 -7
  260. package/components/divider/theming.scss +0 -20
  261. package/components/elevation/style.scss +0 -32
  262. package/components/layout/style.scss +0 -223
  263. package/components/list/style.scss +0 -358
  264. package/components/list/theming.scss +0 -83
  265. package/components/menu/style.scss +0 -280
  266. package/components/menu/theming.scss +0 -80
  267. package/components/navdrawer/index.js +0 -200
  268. package/components/navdrawer/style.scss +0 -595
  269. package/components/navdrawer/theming.scss +0 -62
  270. package/components/progress/style.scss +0 -136
  271. package/components/ripple/index.js +0 -63
  272. package/components/ripple/ripple.scss +0 -122
  273. package/components/selection/style.scss +0 -320
  274. package/components/selection/theming.scss +0 -98
  275. package/components/snackbar/style.scss +0 -212
  276. package/components/switch/style.scss +0 -3
  277. package/components/tab/style.scss +0 -275
  278. package/components/tab/theming.scss +0 -34
  279. package/components/template/theming.scss +0 -31
  280. package/components/textfield/style.scss +0 -795
  281. package/components/textfield/theming.scss +0 -256
  282. package/components/theming/globals.scss +0 -25
  283. package/components/theming/theming.scss +0 -559
  284. package/components/toolbar/style.scss +0 -190
  285. package/components/toolbar/theming.scss +0 -32
  286. package/components/tooltip/style.scss +0 -135
  287. package/components/type/style.scss +0 -167
  288. package/components/type/theming.scss +0 -25
  289. package/docs/bottomnav.html +0 -1
  290. package/docs/bottomnav.min.js +0 -2
  291. package/docs/bottomnav.min.js.map +0 -1
  292. package/docs/button.html +0 -1
  293. package/docs/button.min.js +0 -2
  294. package/docs/button.min.js.map +0 -1
  295. package/docs/card.html +0 -1
  296. package/docs/card.min.js +0 -2
  297. package/docs/card.min.js.map +0 -1
  298. package/docs/components.min.css +0 -1
  299. package/docs/components.min.js +0 -2
  300. package/docs/components.min.js.map +0 -1
  301. package/docs/datatable.html +0 -1
  302. package/docs/datatable.min.js +0 -2
  303. package/docs/datatable.min.js.map +0 -1
  304. package/docs/dialog.html +0 -1
  305. package/docs/dialog.min.js +0 -2
  306. package/docs/dialog.min.js.map +0 -1
  307. package/docs/docs.min.css +0 -1
  308. package/docs/docs.min.js +0 -2
  309. package/docs/docs.min.js.map +0 -1
  310. package/docs/elevation.html +0 -1
  311. package/docs/elevation.min.js +0 -2
  312. package/docs/elevation.min.js.map +0 -1
  313. package/docs/fab.html +0 -1
  314. package/docs/fab.min.js +0 -2
  315. package/docs/fab.min.js.map +0 -1
  316. package/docs/index.html +0 -1
  317. package/docs/index.min.js +0 -2
  318. package/docs/index.min.js.map +0 -1
  319. package/docs/layout.html +0 -1
  320. package/docs/layout.min.js +0 -2
  321. package/docs/layout.min.js.map +0 -1
  322. package/docs/list.html +0 -1
  323. package/docs/list.min.js +0 -2
  324. package/docs/list.min.js.map +0 -1
  325. package/docs/menu.html +0 -1
  326. package/docs/menu.min.js +0 -2
  327. package/docs/menu.min.js.map +0 -1
  328. package/docs/navdrawer.html +0 -1
  329. package/docs/navdrawer.min.js +0 -2
  330. package/docs/navdrawer.min.js.map +0 -1
  331. package/docs/prerender.min.js +0 -2
  332. package/docs/prerender.min.js.map +0 -1
  333. package/docs/progress.html +0 -1
  334. package/docs/progress.min.js +0 -2
  335. package/docs/progress.min.js.map +0 -1
  336. package/docs/search.html +0 -1
  337. package/docs/search.min.js +0 -2
  338. package/docs/search.min.js.map +0 -1
  339. package/docs/selection.html +0 -1
  340. package/docs/selection.min.js +0 -2
  341. package/docs/selection.min.js.map +0 -1
  342. package/docs/slider.html +0 -1
  343. package/docs/slider.min.js +0 -2
  344. package/docs/slider.min.js.map +0 -1
  345. package/docs/snackbar.html +0 -1
  346. package/docs/snackbar.min.js +0 -2
  347. package/docs/snackbar.min.js.map +0 -1
  348. package/docs/src/components/bottomnav.js +0 -16
  349. package/docs/src/components/bottomnav.pug +0 -112
  350. package/docs/src/components/button.js +0 -156
  351. package/docs/src/components/button.pug +0 -194
  352. package/docs/src/components/card.js +0 -136
  353. package/docs/src/components/card.pug +0 -133
  354. package/docs/src/components/datatable.js +0 -183
  355. package/docs/src/components/datatable.pug +0 -324
  356. package/docs/src/components/dialog.pug +0 -138
  357. package/docs/src/components/elevation.js +0 -3
  358. package/docs/src/components/elevation.pug +0 -17
  359. package/docs/src/components/fab.pug +0 -84
  360. package/docs/src/components/layout.js +0 -116
  361. package/docs/src/components/layout.pug +0 -104
  362. package/docs/src/components/list.js +0 -15
  363. package/docs/src/components/list.pug +0 -293
  364. package/docs/src/components/menu.pug +0 -292
  365. package/docs/src/components/navdrawer.js +0 -112
  366. package/docs/src/components/navdrawer.pug +0 -113
  367. package/docs/src/components/progress.pug +0 -17
  368. package/docs/src/components/search.js +0 -206
  369. package/docs/src/components/search.pug +0 -149
  370. package/docs/src/components/selection.js +0 -6
  371. package/docs/src/components/selection.pug +0 -116
  372. package/docs/src/components/slider.js +0 -3
  373. package/docs/src/components/slider.pug +0 -19
  374. package/docs/src/components/snackbar.pug +0 -145
  375. package/docs/src/components/tab.js +0 -137
  376. package/docs/src/components/tab.pug +0 -329
  377. package/docs/src/components/textfield.pug +0 -416
  378. package/docs/src/components/toolbar.js +0 -6
  379. package/docs/src/components/toolbar.pug +0 -86
  380. package/docs/src/components/tooltip.js +0 -6
  381. package/docs/src/components/tooltip.pug +0 -76
  382. package/docs/src/components/type.js +0 -6
  383. package/docs/src/components/type.pug +0 -34
  384. package/docs/src/components.scss +0 -1
  385. package/docs/src/docs.scss +0 -284
  386. package/docs/src/index.js +0 -3
  387. package/docs/src/index.pug +0 -6
  388. package/docs/src/menuoptions.js +0 -136
  389. package/docs/src/mixins.pug +0 -139
  390. package/docs/src/prerender.js +0 -26
  391. package/docs/src/sample-utils.js +0 -108
  392. package/docs/src/targetHandler.js +0 -50
  393. package/docs/src/theming.ie11.scss +0 -18
  394. package/docs/src/theming.scss +0 -18
  395. package/docs/tab.html +0 -1
  396. package/docs/tab.min.js +0 -2
  397. package/docs/tab.min.js.map +0 -1
  398. package/docs/textfield.html +0 -2
  399. package/docs/textfield.min.js +0 -2
  400. package/docs/textfield.min.js.map +0 -1
  401. package/docs/theming.ie11.min.css +0 -1
  402. package/docs/theming.ie11.min.js +0 -2
  403. package/docs/theming.ie11.min.js.map +0 -1
  404. package/docs/theming.min.css +0 -1
  405. package/docs/theming.min.js +0 -2
  406. package/docs/theming.min.js.map +0 -1
  407. package/docs/toolbar.html +0 -1
  408. package/docs/toolbar.min.js +0 -2
  409. package/docs/toolbar.min.js.map +0 -1
  410. package/docs/tooltip.html +0 -1
  411. package/docs/tooltip.min.js +0 -2
  412. package/docs/tooltip.min.js.map +0 -1
  413. package/docs/type.html +0 -1
  414. package/docs/type.min.js +0 -2
  415. package/docs/type.min.js.map +0 -1
  416. package/index.js +0 -16
@@ -1,478 +1,374 @@
1
- import { isRtl, findElementParentByClassName } from '../common/dom';
2
-
3
1
  // https://www.w3.org/TR/wai-aria-practices/#grid
4
2
 
5
- // eslint-disable-next-line import/prefer-default-export
6
- export class DataTable {
7
- /**
8
- * @param {Element} element
9
- * @return {void}
10
- */
11
- static attach(element) {
12
- if (!element.hasAttribute('role')) {
13
- element.setAttribute('role', 'grid');
14
- }
15
- element.setAttribute('mdw-js', '');
16
- const headerRow = DataTable.getHeaderRow(element);
17
- const tbody = DataTable.getTableBody(element);
18
- const cellFocusable = element.hasAttribute('mdw-cell-focusable');
19
- const rowFocusable = element.hasAttribute('mdw-row-focusable');
3
+ import * as Keyboard from '../../core/aria/keyboard.js';
4
+ import * as RovingTabIndex from '../../core/aria/rovingtabindex.js';
20
5
 
21
- headerRow.addEventListener('click', DataTable.onHeaderRowClick);
22
- tbody.addEventListener('keydown', DataTable.onTableBodyKeyDown);
23
- tbody.addEventListener('click', DataTable.onTableBodyClick);
24
- let firstRow = null;
25
- let foundTabbableRow = false;
26
- let firstCell = null;
27
- let foundTabbableCell = false;
28
- for (let i = 0; i < tbody.rows.length; i += 1) {
29
- const row = tbody.rows.item(i);
30
- if (rowFocusable) {
31
- if (!firstRow) {
32
- firstRow = row;
33
- }
34
- if (!foundTabbableRow && row.getAttribute('tabindex') === '0') {
35
- foundTabbableRow = true;
36
- } else {
37
- row.setAttribute('tabindex', '-1');
38
- }
39
- } else {
40
- row.removeAttribute('tabindex');
41
- }
42
- for (let j = 0; j < row.cells.length; j += 1) {
43
- const cell = row.cells.item(j);
44
- if (cellFocusable && !rowFocusable) {
45
- if (!firstCell) {
46
- firstCell = cell;
47
- }
48
- if (!foundTabbableCell && cell.getAttribute('tabindex') === '0') {
49
- foundTabbableCell = true;
50
- } else {
51
- cell.setAttribute('tabindex', '-1');
52
- }
53
- } else {
54
- cell.removeAttribute('tabindex');
55
- }
56
- }
57
- }
58
- if (rowFocusable && !foundTabbableRow && firstRow) {
59
- firstRow.setAttribute('tabindex', '0');
60
- DataTable.dispatchEvent(firstRow, 'mdw:tabindexchanged');
61
- } else if (cellFocusable && !foundTabbableCell && firstCell) {
62
- firstCell.setAttribute('tabindex', '0');
63
- DataTable.dispatchEvent(firstCell, 'mdw:tabindexchanged');
64
- }
6
+ import * as DataTableCell from './cell.js';
7
+ import * as DataTableColumnHeader from './columnheader.js';
8
+ import * as DataTableRow from './row.js';
9
+ import * as DataTableRowHeader from './rowheader.js';
10
+
11
+ export const CELL_TABINDEX_QUERIES = [
12
+ 'td:not([mdw-autofocus-widget])',
13
+ 'th:not([mdw-autofocus-widget])',
14
+ 'td[mdw-autofocus-widget] .mdw-datatable__widget',
15
+ 'th[mdw-autofocus-widget] .mdw-datatable__widget',
16
+ ];
17
+
18
+ /**
19
+ * @param {CustomEvent} event
20
+ * @return {void}
21
+ */
22
+ export function onSelectedChange(event) {
23
+ const selected = event.detail.value === 'true';
24
+ const dataTableElement = /** @type {HTMLElement} */ (event.currentTarget);
25
+ const hasSelection = selected || dataTableElement.querySelector('td[aria-selected="true"],tr[aria-selected="true"]');
26
+ if (hasSelection) {
27
+ dataTableElement.setAttribute('mdw-has-selection', '');
28
+ } else {
29
+ dataTableElement.removeAttribute('mdw-has-selection');
65
30
  }
31
+ }
66
32
 
67
- static onTableBodyClick(event) {
68
- const tbody = event.currentTarget;
69
- const mdwDataTable = findElementParentByClassName(tbody, 'mdw-datatable');
70
- const { target } = event;
71
- if (target instanceof HTMLTableCellElement) {
72
- const cellFocusable = mdwDataTable.hasAttribute('mdw-cell-focusable');
73
- const rowFocusable = mdwDataTable.hasAttribute('mdw-row-focusable');
74
- if (cellFocusable) {
75
- const otherTabIndexes = tbody.querySelectorAll('[tabindex="0"]');
76
- for (let i = 0; i < otherTabIndexes.length; i += 1) {
77
- const otherTabIndexItem = otherTabIndexes.item(i);
78
- if (otherTabIndexItem !== target) {
79
- otherTabIndexItem.setAttribute('tabindex', '-1');
80
- }
81
- }
82
- if (target.getAttribute('tabindex') !== '0') {
83
- target.setAttribute('tabindex', '0');
84
- DataTable.dispatchEvent(target, 'mdw:tabindexchanged');
85
- }
86
- } else if (rowFocusable) {
87
- const otherTabIndexes = tbody.querySelectorAll('[tabindex="0"]');
88
- for (let i = 0; i < otherTabIndexes.length; i += 1) {
89
- const otherTabIndexItem = otherTabIndexes.item(i);
90
- if (otherTabIndexItem !== target.parentElement) {
91
- otherTabIndexItem.setAttribute('tabindex', '-1');
92
- }
93
- }
94
- if (target.parentElement.getAttribute('tabindex') !== '0') {
95
- target.parentElement.setAttribute('tabindex', '0');
96
- DataTable.dispatchEvent(target.parentElement, 'mdw:tabindexchanged');
97
- }
98
- }
99
- return;
33
+ /**
34
+ * @param {Element} datatableElement
35
+ * @return {HTMLElement}
36
+ */
37
+ export function getScroller(datatableElement) {
38
+ let scroller = /** @type {HTMLElement} */ (datatableElement.getElementsByClassName('mdw-datatable__scroller')[0]);
39
+ if (!scroller) {
40
+ scroller = document.createElement('div');
41
+ scroller.classList.add('mdw-datatable__scroller');
42
+ const footer = datatableElement.getElementsByClassName('mdw-datatable__footer')[0];
43
+ if (footer) {
44
+ footer.before(scroller);
45
+ } else {
46
+ datatableElement.appendChild(scroller);
100
47
  }
101
- if (target instanceof HTMLInputElement && target.getAttribute('type') === 'checkbox') {
102
- if (mdwDataTable.hasAttribute('mdw-adapter')) {
103
- return;
104
- }
105
- // Checkbox clicked
106
- const cell = DataTable.findParentCell(target);
107
- if (!cell.hasAttribute('mdw-selector')) {
108
- return;
109
- }
110
- event.stopPropagation();
111
- const currentRow = cell.parentElement;
112
- let hasSelection = false;
113
- if (target.checked) {
114
- currentRow.setAttribute('mdw-selected', '');
115
- hasSelection = true;
116
- } else {
117
- currentRow.removeAttribute('mdw-selected');
118
- /** @type {NodeListOf<HTMLInputElement>} */
119
- const checkboxes = (mdwDataTable.querySelectorAll('td[mdw-selector] input[type=checkbox]'));
120
- for (let i = 0; i < checkboxes.length; i += 1) {
121
- if (checkboxes.item(i).checked) {
122
- hasSelection = true;
123
- break;
124
- }
125
- }
126
- }
127
- if (hasSelection) {
128
- mdwDataTable.setAttribute('mdw-has-selection', '');
129
- } else {
130
- mdwDataTable.removeAttribute('mdw-has-selection');
131
- }
48
+ // Move table into scroller if it exists
49
+ const table = datatableElement.getElementsByTagName('table')[0];
50
+ if (table) {
51
+ table.remove();
52
+ scroller.appendChild(table);
132
53
  }
133
54
  }
55
+ return scroller;
56
+ }
134
57
 
135
- /**
136
- * @param {Element} element
137
- * @return {HTMLTableCellElement}
138
- */
139
- static findParentCell(element) {
140
- let el = element;
141
- while (el != null) {
142
- if (el instanceof HTMLTableElement) {
143
- return null;
144
- }
145
- if (el instanceof HTMLTableCellElement) {
146
- return el;
147
- }
148
- el = el.parentElement;
149
- }
150
- return null;
58
+ /**
59
+ * @param {Element} datatableElement
60
+ * @return {HTMLTableElement}
61
+ */
62
+ export function getTable(datatableElement) {
63
+ if (datatableElement instanceof HTMLTableElement) {
64
+ return datatableElement;
151
65
  }
66
+ let table = datatableElement.getElementsByTagName('table')[0];
67
+ if (!table) {
68
+ const scroller = getScroller(datatableElement);
69
+ table = document.createElement('table');
70
+ scroller.appendChild(table);
71
+ }
72
+ return table;
73
+ }
152
74
 
153
- static onHeaderRowClick(event) {
154
- const cell = DataTable.findParentCell(event.target);
155
- if (!cell) {
156
- return;
157
- }
158
- if (cell.cellIndex === -1) {
159
- return;
160
- }
161
- if (!cell.hasAttribute('mdw-sortable')) {
162
- return;
163
- }
164
- const mdwTable = findElementParentByClassName(event.currentTarget, 'mdw-datatable');
165
- if (!mdwTable) {
166
- return;
167
- }
168
- if (mdwTable.hasAttribute('mdw-adapter')) {
169
- return;
170
- }
171
- let ascending = true;
172
- if (cell.hasAttribute('mdw-sorted') && !cell.getAttribute('mdw-sorted')) {
173
- ascending = false;
174
- }
175
- if (ascending) {
176
- cell.setAttribute('mdw-sorted', '');
177
- } else {
178
- cell.setAttribute('mdw-sorted', 'desc');
179
- }
180
- const thItems = cell.parentElement.getElementsByTagName('th');
181
- for (let i = 0; i < thItems.length; i += 1) {
182
- const th = thItems[i];
183
- if (th !== cell) {
184
- th.removeAttribute('mdw-sorted');
185
- }
186
- }
75
+ /**
76
+ * @param {Element} datatableElement
77
+ * @return {HTMLTableSectionElement}
78
+ */
79
+ export function getTableBody(datatableElement) {
80
+ let tbody = datatableElement.getElementsByTagName('tbody')[0];
81
+ if (!tbody) {
82
+ const table = getTable(datatableElement);
83
+ tbody = document.createElement('tbody');
84
+ table.appendChild(tbody);
85
+ }
86
+ return tbody;
87
+ }
187
88
 
188
- /** @type {HTMLTableSectionElement} */
189
- const tbody = DataTable.getTableBody(mdwTable);
190
- const rows = [];
191
- for (let i = tbody.rows.length - 1; i >= 0; i -= 1) {
192
- rows.push(tbody.rows.item(i));
193
- tbody.deleteRow(i);
194
- }
195
- rows.sort((a, b) => {
196
- const aCell = a.cells.item(cell.cellIndex);
197
- const bCell = b.cells.item(cell.cellIndex);
198
- const aText = aCell.textContent;
199
- const bText = bCell.textContent;
200
- if (aCell.dataset.type === 'number') {
201
- return parseFloat(bText) - parseFloat(aText);
202
- }
203
- return bText.localeCompare(aText);
204
- });
205
- if (ascending) {
206
- rows.reverse();
89
+ /**
90
+ * @param {Element} datatableElement
91
+ * @param {number} columnIndex
92
+ * @param {boolean} ascending
93
+ * @return {void}
94
+ */
95
+ export function sortColumn(datatableElement, columnIndex, ascending = true) {
96
+ if (datatableElement.hasAttribute('mdw-datatable-adapter')) {
97
+ return;
98
+ }
99
+ for (const th of datatableElement.getElementsByTagName('th')) {
100
+ if (th.cellIndex === columnIndex) {
101
+ th.setAttribute('aria-sort', ascending ? 'ascending' : 'descending');
102
+ } else if (th.hasAttribute('aria-sort')) {
103
+ th.setAttribute('aria-sort', 'none');
207
104
  }
208
- const fragment = document.createDocumentFragment();
209
- rows.forEach((row) => {
210
- fragment.appendChild(row);
211
- });
212
- tbody.appendChild(fragment);
213
- event.stopPropagation();
214
105
  }
215
106
 
216
- /**
217
- * @param {Element} element
218
- * @param {string} type
219
- * @return {void}
220
- */
221
- static dispatchEvent(element, type) {
222
- const event = document.createEvent('Event');
223
- event.initEvent(type, true, true);
224
- element.dispatchEvent(event);
107
+ /** @type {HTMLTableSectionElement} */
108
+ const tbody = getTableBody(datatableElement);
109
+ const rows = [];
110
+ let i = tbody.rows.length;
111
+ while (i--) {
112
+ rows.push(tbody.rows.item(i));
113
+ tbody.deleteRow(i);
114
+ }
115
+ rows.sort((a, b) => {
116
+ const aCell = a.cells.item(columnIndex);
117
+ const bCell = b.cells.item(columnIndex);
118
+ const aText = aCell.textContent;
119
+ const bText = bCell.textContent;
120
+ if (aCell.dataset.type === 'number') {
121
+ return Number.parseFloat(bText) - Number.parseFloat(aText);
122
+ }
123
+ return bText.localeCompare(aText);
124
+ });
125
+ if (ascending) {
126
+ rows.reverse();
225
127
  }
128
+ const fragment = document.createDocumentFragment();
129
+ for (const row of rows) {
130
+ fragment.appendChild(row);
131
+ }
132
+ tbody.appendChild(fragment);
133
+ }
226
134
 
227
- static onTableBodyKeyDown(event) {
228
- const currentSelection = document.activeElement;
229
- let cellIndex = 0;
230
- /** @type {HTMLTableRowElement} */
231
- let row = null;
232
- let isRow = false;
233
- if (currentSelection instanceof HTMLTableCellElement) {
234
- ({ cellIndex } = currentSelection);
235
- /** @type {HTMLTableRowElement} */
236
- row = (currentSelection.parentElement);
237
- } else if (currentSelection instanceof HTMLTableRowElement) {
238
- isRow = true;
239
- row = currentSelection;
240
- }
241
- if (!row) {
242
- return;
243
- }
244
- /** @type {HTMLTableSectionElement} */
245
- const tbody = event.currentTarget;
246
- if (event.key === 'ArrowUp' || (event.key === 'Up')) {
247
- if (row.sectionRowIndex === 0) {
248
- return;
249
- }
250
- event.stopPropagation();
251
- event.preventDefault();
252
- const newIndex = row.sectionRowIndex - 1;
253
- const newRow = tbody.rows.item(newIndex);
254
- currentSelection.setAttribute('tabindex', '-1');
255
- if (isRow) {
256
- newRow.focus();
257
- newRow.setAttribute('tabindex', '0');
258
- DataTable.dispatchEvent(newRow, 'mdw:tabindexchanged');
259
- } else {
260
- newRow.cells.item(cellIndex).focus();
261
- newRow.cells.item(cellIndex).setAttribute('tabindex', '0');
262
- DataTable.dispatchEvent(newRow.cells.item(cellIndex), 'mdw:tabindexchanged');
263
- }
264
- return;
265
- }
266
- if (event.key === 'ArrowDown' || (event.key === 'Down')) {
267
- const newIndex = row.sectionRowIndex + 1;
268
- if (newIndex >= tbody.rows.length) {
269
- return;
270
- }
271
- event.stopPropagation();
272
- event.preventDefault();
273
- const newRow = tbody.rows.item(newIndex);
274
- currentSelection.setAttribute('tabindex', '-1');
275
- if (isRow) {
276
- newRow.focus();
277
- newRow.setAttribute('tabindex', '0');
278
- DataTable.dispatchEvent(newRow, 'mdw:tabindexchanged');
279
- } else {
280
- newRow.cells.item(cellIndex).focus();
281
- newRow.cells.item(cellIndex).setAttribute('tabindex', '0');
282
- DataTable.dispatchEvent(newRow.cells.item(cellIndex), 'mdw:tabindexchanged');
283
- }
284
- return;
285
- }
286
- if (event.ctrlKey && event.key === 'Home') {
287
- if (row.sectionRowIndex === 0 && cellIndex === 0) {
288
- return;
289
- }
290
- event.stopPropagation();
291
- event.preventDefault();
292
- const newRow = tbody.rows.item(0);
293
- currentSelection.setAttribute('tabindex', '-1');
294
- if (isRow) {
295
- newRow.focus();
296
- newRow.setAttribute('tabindex', '0');
297
- DataTable.dispatchEvent(newRow, 'mdw:tabindexchanged');
298
- } else {
299
- newRow.cells.item(0).focus();
300
- newRow.cells.item(0).setAttribute('tabindex', '0');
301
- DataTable.dispatchEvent(newRow.cells.item(0), 'mdw:tabindexchanged');
302
- }
303
- return;
304
- }
305
- if (event.ctrlKey && event.key === 'End') {
306
- const newRowIndex = tbody.rows.length - 1;
307
- let newCellIndex = 0;
308
- if (!isRow) {
309
- newCellIndex = row.cells.length - 1;
310
- }
311
- if (row.sectionRowIndex === newRowIndex && cellIndex === newCellIndex) {
312
- return;
313
- }
314
- event.stopPropagation();
315
- event.preventDefault();
316
- const newRow = tbody.rows.item(newRowIndex);
317
- currentSelection.setAttribute('tabindex', '-1');
318
- if (isRow) {
319
- newRow.focus();
320
- newRow.setAttribute('tabindex', '0');
321
- DataTable.dispatchEvent(newRow, 'mdw:tabindexchanged');
322
- } else {
323
- newRow.cells.item(newCellIndex).focus();
324
- newRow.cells.item(newCellIndex).setAttribute('tabindex', '0');
325
- DataTable.dispatchEvent(newRow.cells.item(newCellIndex), 'mdw:tabindexchanged');
326
- }
327
- return;
328
- }
329
- if (event.key === 'Home') {
330
- if (isRow) {
331
- return;
332
- }
333
- if (cellIndex === 0) {
334
- return;
335
- }
336
- event.stopPropagation();
337
- event.preventDefault();
338
- const newIndex = 0;
339
- const newCell = row.cells.item(newIndex);
340
- currentSelection.setAttribute('tabindex', '-1');
341
- newCell.focus();
342
- newCell.setAttribute('tabindex', '0');
343
- DataTable.dispatchEvent(newCell, 'mdw:tabindexchanged');
344
- return;
345
- }
346
- if (event.key === 'End') {
347
- if (isRow) {
348
- return;
349
- }
350
- const newIndex = row.cells.length - 1;
351
- if (newIndex === cellIndex) {
352
- return;
353
- }
354
- event.stopPropagation();
355
- event.preventDefault();
356
- const newCell = row.cells.item(newIndex);
357
- currentSelection.setAttribute('tabindex', '-1');
358
- newCell.focus();
359
- newCell.setAttribute('tabindex', '0');
360
- DataTable.dispatchEvent(newCell, 'mdw:tabindexchanged');
361
- return;
362
- }
363
- const isRtlEnabled = isRtl();
364
- let isLeft = false;
365
- let isRight = false;
366
- if (event.key === 'ArrowLeft' || (event.key === 'Left')) {
367
- if (isRtlEnabled) {
368
- isRight = true;
369
- } else {
370
- isLeft = true;
371
- }
372
- }
373
- if (event.key === 'ArrowRight' || (event.key === 'Right')) {
374
- if (isRtlEnabled) {
375
- isLeft = true;
376
- } else {
377
- isRight = true;
378
- }
135
+ /**
136
+ * @param {CustomEvent} event
137
+ * @return {void}
138
+ */
139
+ export function onItemFocus(event) {
140
+ const datatableElement = /** @type {HTMLElement} */ (event.currentTarget);
141
+ const onFocusInteraction = datatableElement.getAttribute('mdw-on-focus');
142
+ if (!onFocusInteraction) {
143
+ return;
144
+ }
145
+ const itemElement = /** @type {HTMLElement} */ (event.target);
146
+ if (itemElement.getAttribute('aria-disabled') === 'true') {
147
+ return;
148
+ }
149
+ for (const interaction of onFocusInteraction.split(' ')) {
150
+ switch (interaction) {
151
+ case 'select':
152
+ if (itemElement instanceof HTMLTableRowElement) {
153
+ DataTableRow.setSelected(itemElement, true);
154
+ } else {
155
+ DataTableCell.setSelected(itemElement, true);
156
+ }
157
+ break;
158
+ default:
379
159
  }
380
- if (isLeft) {
381
- if (isRow) {
160
+ }
161
+ }
162
+
163
+ /**
164
+ * @param {CustomEvent} event
165
+ * @return {void}
166
+ */
167
+ export function onSort(event) {
168
+ const datatableElement = /** @type {HTMLElement} */ (event.currentTarget);
169
+ const cell = /** @type {HTMLTableHeaderCellElement} */ (event.target);
170
+ sortColumn(datatableElement, cell.cellIndex, event.detail.sort === 'ascending');
171
+ }
172
+
173
+ /**
174
+ * @param {CustomEvent} event
175
+ * @return {void}
176
+ */
177
+ export function onRowHeaderCheckedChange(event) {
178
+ const cell = /** @type {HTMLTableHeaderCellElement} */ (event.target);
179
+ const row = cell.parentElement;
180
+ DataTableRow.setSelected(row, event.detail.value);
181
+ }
182
+
183
+ /**
184
+ * @param {Event} event
185
+ * @return {void}
186
+ */
187
+ function onTabIndexZeroed(event) {
188
+ const dataTableElement = /** @type {HTMLElement} */ (event.currentTarget);
189
+ const emitter = /** @type {HTMLElement} */ (event.target);
190
+
191
+ const row = (emitter instanceof HTMLTableRowElement && emitter);
192
+ const cell = (!row && emitter instanceof HTMLTableCellElement && emitter);
193
+ if (!row && !cell) {
194
+ return;
195
+ }
196
+ event.stopPropagation();
197
+ RovingTabIndex.removeTabIndex(dataTableElement.querySelectorAll(row ? 'tr' : CELL_TABINDEX_QUERIES.join(',')), [emitter]);
198
+ }
199
+
200
+ /**
201
+ * @param {CustomEvent} event
202
+ * @return {void}
203
+ */
204
+ export function onKeyboard(event) {
205
+ const dataTableElement = /** @type {HTMLElement} */ (event.currentTarget);
206
+ const emitter = /** @type {HTMLElement} */ (event.target);
207
+ let current = document.activeElement;
208
+
209
+ let row = (emitter instanceof HTMLTableRowElement && emitter);
210
+ const cell = (!row && emitter instanceof HTMLTableCellElement && emitter);
211
+ if (!row && !cell) {
212
+ return;
213
+ }
214
+ if (!row) {
215
+ row = /** @type {HTMLTableRowElement} */ (cell.parentElement);
216
+ }
217
+
218
+ let checkNavKeys = false;
219
+ switch (event.type) {
220
+ case Keyboard.SPACEBAR_KEY:
221
+ if (event.detail.ctrlKey || event.detail.altKey || event.detail.metaKey) {
382
222
  return;
383
223
  }
384
- if (cellIndex === 0) {
224
+ if (!event.detail.shiftKey) {
385
225
  return;
386
226
  }
387
- event.stopPropagation();
388
- event.preventDefault();
389
- const newIndex = cellIndex - 1;
390
- const newCell = row.cells.item(newIndex);
391
- currentSelection.setAttribute('tabindex', '-1');
392
- newCell.focus();
393
- newCell.setAttribute('tabindex', '0');
394
- DataTable.dispatchEvent(newCell, 'mdw:tabindexchanged');
395
- return;
396
- }
397
- if (isRight) {
398
- if (isRow) {
227
+ if (!row.hasAttribute('aria-selected')) {
399
228
  return;
400
229
  }
401
- const newIndex = cellIndex + 1;
402
- if (newIndex >= row.cells.length) {
230
+ DataTableRow.setSelected(row, row.getAttribute('aria-selected') !== 'true', true);
231
+ break;
232
+ default:
233
+ checkNavKeys = true;
234
+ }
235
+
236
+ if (checkNavKeys) {
237
+ // Keyboard Navigation
238
+ /** @type {Iterable<HTMLElement>} */
239
+ let searchElements;
240
+ let reverse = false;
241
+ let loop = false;
242
+ switch (event.type) {
243
+ case Keyboard.UP_ARROW_KEY:
244
+ reverse = true;
245
+ // Fallthrough
246
+ case Keyboard.DOWN_ARROW_KEY:
247
+ if (event.detail.ctrlKey || event.detail.altKey || event.detail.metaKey) {
248
+ return;
249
+ }
250
+ if (cell) {
251
+ searchElements = getTableBody(dataTableElement).querySelectorAll(
252
+ CELL_TABINDEX_QUERIES.map((q) => `${q}:nth-child(${cell.cellIndex + 1})`).join(','),
253
+ );
254
+ } else {
255
+ searchElements = getTableBody(dataTableElement).getElementsByTagName('tr');
256
+ }
257
+ break;
258
+ case Keyboard.BACK_ARROW_KEY:
259
+ reverse = true;
260
+ // Fallthrough
261
+ case Keyboard.FORWARD_ARROW_KEY:
262
+ if (event.detail.ctrlKey || event.detail.altKey || event.detail.metaKey) {
263
+ return;
264
+ }
265
+ if (!cell) {
266
+ return;
267
+ }
268
+ searchElements = cell.parentElement.querySelectorAll(CELL_TABINDEX_QUERIES.join(','));
269
+ break;
270
+ case Keyboard.END_KEY:
271
+ reverse = true;
272
+ // Fallthrough
273
+ case Keyboard.HOME_KEY:
274
+ if (event.detail.altKey || event.detail.metaKey) {
275
+ return;
276
+ }
277
+ if (!cell) {
278
+ return;
279
+ }
280
+ searchElements = event.detail.ctrlKey
281
+ ? getTableBody(dataTableElement).querySelectorAll(CELL_TABINDEX_QUERIES.join(','))
282
+ : cell.parentElement.querySelectorAll(CELL_TABINDEX_QUERIES.join(','));
283
+ cell.setAttribute('tabindex', '-1');
284
+ current = null;
285
+ loop = true;
286
+ break;
287
+ default:
403
288
  return;
404
- }
405
- event.stopPropagation();
406
- event.preventDefault();
407
- const newCell = row.cells.item(newIndex);
408
- currentSelection.setAttribute('tabindex', '-1');
409
- newCell.focus();
410
- newCell.setAttribute('tabindex', '0');
411
- DataTable.dispatchEvent(newCell, 'mdw:tabindexchanged');
412
289
  }
290
+ RovingTabIndex.selectNext(searchElements, current, loop, reverse);
413
291
  }
414
292
 
415
- static detach(element) {
416
- element.removeAttribute('mdw-js');
417
- const headerRow = DataTable.getHeaderRow(element);
418
- const tbody = DataTable.getTableBody(element);
419
- headerRow.removeEventListener('click', DataTable.onHeaderRowClick);
420
- tbody.removeEventListener('keydown', DataTable.onTableBodyKeyDown);
421
- tbody.removeEventListener('click', DataTable.onTableBodyClick);
422
- }
293
+ event.preventDefault();
294
+ event.stopPropagation();
295
+ }
423
296
 
297
+ /**
298
+ * @param {Element} element
299
+ * @return {void}
300
+ */
301
+ export function detach(element) {
302
+ element.removeAttribute('mdw-datatable-js');
303
+ element.removeEventListener(DataTableRow.FOCUS_EVENT, onItemFocus);
304
+ element.removeEventListener(DataTableCell.FOCUS_EVENT, onItemFocus);
305
+ element.removeEventListener(DataTableColumnHeader.SORT_EVENT, onSort);
306
+ element.removeEventListener(Keyboard.UP_ARROW_KEY, onKeyboard);
307
+ element.removeEventListener(Keyboard.DOWN_ARROW_KEY, onKeyboard);
308
+ element.removeEventListener(Keyboard.FORWARD_ARROW_KEY, onKeyboard);
309
+ element.removeEventListener(Keyboard.BACK_ARROW_KEY, onKeyboard);
310
+ element.removeEventListener(Keyboard.HOME_KEY, onKeyboard);
311
+ element.removeEventListener(Keyboard.END_KEY, onKeyboard);
312
+ element.removeEventListener(RovingTabIndex.TABINDEX_ZEROED, onTabIndexZeroed);
313
+ }
424
314
 
425
- /**
426
- * @param {Element} tableElement
427
- * @return {HTMLTableElement}
428
- */
429
- static getTable(tableElement) {
430
- if (tableElement instanceof HTMLTableElement) {
431
- return tableElement;
432
- }
433
- let table = tableElement.getElementsByTagName('table')[0];
434
- if (!table) {
435
- table = document.createElement('table');
436
- const footer = tableElement.getElementsByClassName('mdw-datatable__footer')[0];
437
- if (footer) {
438
- tableElement.insertBefore(table, footer);
439
- } else {
440
- tableElement.appendChild(table);
441
- }
442
- }
443
- return table;
315
+ /**
316
+ * @param {Element} tableElement
317
+ * @return {HTMLTableRowElement}
318
+ */
319
+ export function getHeaderRow(tableElement) {
320
+ let thead = tableElement.getElementsByTagName('thead')[0];
321
+ if (!thead) {
322
+ const table = getTable(tableElement);
323
+ thead = document.createElement('thead');
324
+ table.appendChild(thead);
444
325
  }
445
-
446
- /**
447
- * @param {Element} tableElement
448
- * @return {HTMLTableRowElement}
449
- */
450
- static getHeaderRow(tableElement) {
451
- let thead = tableElement.getElementsByTagName('thead')[0];
452
- if (!thead) {
453
- const table = DataTable.getTable(tableElement);
454
- thead = document.createElement('thead');
455
- table.appendChild(thead);
456
- }
457
- let headerRow = thead.getElementsByTagName('tr')[0];
458
- if (!headerRow) {
459
- headerRow = document.createElement('tr');
460
- thead.appendChild(headerRow);
461
- }
462
- return headerRow;
326
+ let headerRow = thead.getElementsByTagName('tr')[0];
327
+ if (!headerRow) {
328
+ headerRow = document.createElement('tr');
329
+ thead.appendChild(headerRow);
463
330
  }
331
+ return headerRow;
332
+ }
464
333
 
465
- /**
466
- * @param {Element} tableElement
467
- * @return {HTMLTableSectionElement}
468
- */
469
- static getTableBody(tableElement) {
470
- let tbody = tableElement.getElementsByTagName('tbody')[0];
471
- if (!tbody) {
472
- const table = DataTable.getTable(tableElement);
473
- tbody = document.createElement('tbody');
474
- table.appendChild(tbody);
475
- }
476
- return tbody;
334
+ /**
335
+ * @param {Element} element
336
+ * @return {void}
337
+ */
338
+ export function attach(element) {
339
+ element.setAttribute('mdw-datatable-js', '');
340
+
341
+ const table = getTable(element);
342
+ table.setAttribute('role', 'grid');
343
+ const headerRow = getHeaderRow(element);
344
+ const tbody = getTableBody(element);
345
+
346
+ for (const el of headerRow.getElementsByTagName('th')) DataTableColumnHeader.attach(el);
347
+ for (const el of tbody.getElementsByTagName('th')) DataTableRowHeader.attach(el);
348
+
349
+ const tableRows = tbody.getElementsByTagName('tr');
350
+ for (const el of tableRows) DataTableRow.attach(el);
351
+
352
+ const rowFocusable = element.hasAttribute('mdw-row-focusable');
353
+ if (rowFocusable) {
354
+ RovingTabIndex.setupTabIndexes(tableRows);
477
355
  }
356
+ const cellFocusable = element.hasAttribute('mdw-cell-focusable');
357
+ if (cellFocusable) {
358
+ RovingTabIndex.setupTabIndexes(tbody.querySelectorAll(CELL_TABINDEX_QUERIES.join(',')));
359
+ }
360
+
361
+ element.addEventListener(DataTableRow.FOCUS_EVENT, onItemFocus);
362
+ element.addEventListener(DataTableRow.SELECTED_CHANGE_EVENT, onSelectedChange);
363
+ element.addEventListener(DataTableCell.FOCUS_EVENT, onItemFocus);
364
+ element.addEventListener(DataTableCell.SELECTED_CHANGE_EVENT, onSelectedChange);
365
+ element.addEventListener(DataTableColumnHeader.SORT_EVENT, onSort);
366
+ element.addEventListener(Keyboard.SPACEBAR_KEY, onKeyboard);
367
+ element.addEventListener(Keyboard.UP_ARROW_KEY, onKeyboard);
368
+ element.addEventListener(Keyboard.DOWN_ARROW_KEY, onKeyboard);
369
+ element.addEventListener(Keyboard.FORWARD_ARROW_KEY, onKeyboard);
370
+ element.addEventListener(Keyboard.BACK_ARROW_KEY, onKeyboard);
371
+ element.addEventListener(Keyboard.HOME_KEY, onKeyboard);
372
+ element.addEventListener(Keyboard.END_KEY, onKeyboard);
373
+ element.addEventListener(RovingTabIndex.TABINDEX_ZEROED, onTabIndexZeroed);
478
374
  }