Autocomplete.svelte 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <script>
  2. import { view, schueler, db } from "./../stores.js";
  3. import { get_kurs, get_schueler } from './../getter.js';
  4. import Schueler from "./Schueler.svelte";
  5. import Kurs from "./Kurs.svelte";
  6. let input;
  7. let term = "";
  8. let res = [];
  9. let selected = -1;
  10. let items = [];
  11. let show;
  12. $: if (term.length > 1) {
  13. selected = -1;
  14. const schueler = $db
  15. .prepare(
  16. `SELECT *
  17. FROM schueler
  18. WHERE vorname || ' ' || name LIKE $term
  19. OR name || ', ' || vorname LIKE $term`
  20. )
  21. .all({term: "%"+ term + "%"});
  22. const kurse = $db
  23. .prepare(
  24. `SELECT DISTINCT k.kurs, s.klasse, s.jahr
  25. FROM kurszugehoerigkeit AS k
  26. JOIN schueler AS s ON (s.schild_id = k.schild_id)
  27. WHERE kurs LIKE $term OR klasse LIKE $term`
  28. )
  29. .all({term: term + "%"});
  30. const res_s = schueler.map(s => {
  31. return { id: s.id, name: `${s.name}, ${s.vorname}`, schueler: true };
  32. });
  33. const res_k = kurse.map(k => {
  34. return {
  35. id: k.kurs,
  36. name: `${k.kurs} – ${k.klasse}`,
  37. klasse: k.klasse,
  38. jahr: k.jahr
  39. };
  40. });
  41. res = res_k.concat(res_s);
  42. }
  43. $: if (term.length < 2) res = [];
  44. const key = e => {
  45. if (e.key === "ArrowDown") selected += 1;
  46. else if (e.key === "ArrowUp") selected -= 1;
  47. else if (e.key === "Enter" && selected >= 0) {
  48. show_selected(res[selected]);
  49. return;
  50. } else return;
  51. if (selected > res.length - 1) selected = 0;
  52. if (selected < 0) selected = res.length - 1;
  53. e.preventDefault();
  54. items[selected].scrollIntoView({ block: "center", inline: "nearest" });
  55. };
  56. const blur = _ => {
  57. setTimeout(_ => (show = false), 500);
  58. };
  59. function show_selected(item) {
  60. res = [];
  61. selected = -1;
  62. term = "";
  63. input.blur();
  64. // hole Schüler
  65. if (item.schueler) {
  66. get_schueler(item);
  67. $view = Schueler;
  68. }
  69. // hole Kurs
  70. else {
  71. get_kurs(item);
  72. $view = Kurs;
  73. }
  74. }
  75. </script>
  76. <style>
  77. .wrapper {
  78. position: relative;
  79. }
  80. .input {
  81. width: 20rem;
  82. }
  83. .items {
  84. position: absolute;
  85. border: 1px solid #d4d4d4;
  86. z-index: 99;
  87. top: 100%;
  88. left: 0;
  89. right: 0;
  90. max-height: 80vh;
  91. overflow: auto;
  92. }
  93. .items div {
  94. padding: 10px;
  95. cursor: pointer;
  96. background-color: #fff;
  97. border-bottom: 1px solid #d4d4d4;
  98. }
  99. .items div:hover {
  100. background-color: #e9e9e9;
  101. }
  102. .active {
  103. background-color: DodgerBlue !important;
  104. color: #ffffff;
  105. }
  106. </style>
  107. <div class="wrapper">
  108. <input
  109. class="input"
  110. type="text"
  111. placeholder="suchen ..."
  112. bind:this={input}
  113. bind:value={term}
  114. on:keydown={key}
  115. on:blur={blur}
  116. on:focus={() => (show = true)} />
  117. {#if res.length && show}
  118. <div class="items">
  119. {#each res as r, i}
  120. <div
  121. on:click={() => show_selected(r)}
  122. class:active={selected === i}
  123. bind:this={items[i]}>
  124. {r.name}
  125. </div>
  126. {/each}
  127. </div>
  128. {/if}
  129. </div>