From fc5e4eb54e4d076f61eead5bf753d6b1fe49675d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiesner=20Andr=C3=A1s?= Date: Thu, 2 Jun 2022 12:08:10 +0200 Subject: [PATCH] =?UTF-8?q?Keres=C5=91=20m=C5=B1k=C3=B6dik,=20sz=C3=ADnez?= =?UTF-8?q?=C3=A9ssel,=20csoportkiv=C3=A1laszt=C3=A1ssal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.php | 7 ++-- interface.php | 58 ++++++++++++++++++++++++-- js/mkkkvv.js | 112 ++++++++++++++++++++++++++++++++++++++++++-------- js/o.js | 25 +++++++++++ mkkkvv.css | 39 +++++++++++++++++- 5 files changed, 215 insertions(+), 26 deletions(-) create mode 100644 js/o.js diff --git a/index.php b/index.php index c5ef5a2..b4b845d 100644 --- a/index.php +++ b/index.php @@ -8,15 +8,16 @@ MKK Közivezető-választás +
- -
+ +
-
diff --git a/interface.php b/interface.php index 74cc353..2712f21 100644 --- a/interface.php +++ b/interface.php @@ -31,23 +31,35 @@ function read_electable_people(string $fname): array } define("MINIMUM_NEEDLE_LENGTH", 3); +define("HIDE_GROUP_OF_NON_DUPLICATES", true); // keresés a nevek között -function search_in_names(array $records, string $needle): array +function search_in_names(array $records, string $needle, string $group = ""): array { + // keresés $needle = trim($needle); if (strlen($needle) < MINIMUM_NEEDLE_LENGTH) { return []; } + $exact_match = []; $hitpos_array = []; - $filter = function(array $var) use (&$hitpos_array, $needle) : bool { + $filter = function (array $var) use (&$hitpos_array, &$exact_match, $needle, $group): bool { + // ha a csoporton belül keres + if ($group !== "" && $var["group"] !== $group) { + return false; + } + $hitpos = stripos($var["name"], $needle); - if ($hitpos != false) { + // ha van egyezés... + if ($hitpos !== false) { $hitpos_array[] = $hitpos; + + // megvizsgálja, hogy exact egyezés van-e? + $exact_match[] = $var["name"] === $needle; } return $hitpos !== false; @@ -58,9 +70,46 @@ function search_in_names(array $records, string $needle): array if (count($filter_res) > 0) { for ($i = 0; $i < count($filter_res); $i++) { $filter_res[$i]["hitpos"] = $hitpos_array[$i]; + $filter_res[$i]["exact_match"] = $exact_match[$i]; + $filter_res[$i]["duplicate"] = false; } } + if (HIDE_GROUP_OF_NON_DUPLICATES) { + // nevek rendezése hossz szerint (substr gyorsítása n*(n-1)-ről (n-1)+(n-2)+(n-3)... vizsgálatra) + usort($filter_res, fn($a, $b) => strlen($a["name"]) - strlen($b["name"])); + + // ha a név nem szerepel több, mint egyszer, akkor a csoportot törli (security reasons) + for ($i = 0; $i < count($filter_res); $i++) { + if ($filter_res[$i]["duplicate"]) { + continue; + } + + $name_needle = $filter_res[$i]["name"]; // név, amit keresünk a többiben + $is_duplicate = false; + for ($j = $i + 1; $j < count($filter_res); $j++) { + // ha van találat, akkor kiugrunk a keresésből + if (stripos($filter_res[$j]["name"], $name_needle) !== false) { + $filter_res[$j]["duplicate"] = true; + $is_duplicate = true; + break; + } + } + + $filter_res[$i]["duplicate"] = $is_duplicate; + } + + // csoport törlése azokból a nevekből, amikből nem szerepel több + for ($i = 0; $i < count($filter_res); $i++) { + if (!$filter_res[$i]["duplicate"]) { + $filter_res[$i]["group"] = ""; + } + } + } + + // rendezés abc-rendbe + usort($filter_res, fn($a, $b) => $a["name"] > $b["name"]); + return $filter_res; } @@ -76,8 +125,9 @@ switch ($action) { case "search": { $needle = json_decode($_POST["needle"]); + $group = json_decode($_POST["group"]); $p = read_electable_people(ELECTABLE_PEOPLE_DATABASE); - $hits = search_in_names($p, $needle); + $hits = search_in_names($p, $needle, $group); $res = $hits; } break; diff --git a/js/mkkkvv.js b/js/mkkkvv.js index ccb1a98..c961507 100644 --- a/js/mkkkvv.js +++ b/js/mkkkvv.js @@ -1,39 +1,54 @@ const MINIMUM_NEEDLE_LENGTH = 3; -const CANVAS = document.create - // keresés indítása a nevek között function search_in_names(needle) { let hintbox = document.getElementById("hintbox"); - if (needle.length < 3) { - hintbox.innerHTML = ""; - } - if (needle.trim().length < MINIMUM_NEEDLE_LENGTH) { + hintbox.innerHTML = ""; + hide("hintzone"); + o("nameinput").setAttribute("validity", ""); return; } - request({ + let request_data = { action: "search", - needle: needle - }).then(resp => { + needle: "", + group: "" + }; + + // csoport és név szétválasztása + let group_regex = /(\[[a-záéíóöúü]+\]$)/gi; + let group_extracted = needle.match(group_regex); + if (group_extracted != null) { + request_data["group"] = group_extracted[0].substring(1, group_extracted[0].length - 1); + request_data["needle"] = needle.substring(0, needle.length - group_extracted[0].length - 1).trim(); + } else { + request_data["needle"] = needle; + } + + request(request_data).then(resp => { hintbox.innerHTML = ""; let hits = JSON.parse(resp); - console.log(hits); - hits.forEach((key, val) => { + hits.forEach((val) => { if (needle.length < 3) { return; } let hit = document.createElement("span"); hit.classList.add("hit"); + hit.addEventListener("click", () => { + let group_id = val["duplicate"] ? ` [${val["group"]}]` : ""; + fill_name_input(`${val["name"]}${group_id}`); + hide("hintzone"); + ninput.setAttribute("validity", "ok"); + }); let name_node = document.createElement("span"); name_node.classList.add("name"); - let hp = key["hitpos"]; - let name = key["name"]; + let hp = val["hitpos"]; + let name = val["name"]; if (hp > 0) { let name_begin = name.slice(0, hp); @@ -52,12 +67,73 @@ function search_in_names(needle) { hit.appendChild(name_node); - let group = document.createElement("span"); - group.innerText = `(${key["group"]})`; - group.classList.add("group"); - hit.appendChild(group); + let group = val["group"]; + if (group.length > 0) { + let group_node = document.createElement("span"); + group_node.innerHTML = ` ${print_from_group(group)}`; + group_node.classList.add("group"); + hit.appendChild(group_node); + } hintbox.appendChild(hit); }); + + // doboz megjelenítése, ha szükséges + hits.length > 0 ? show("hintzone") : hide("hintzone"); + + // szövegmező színezése + let validity = ""; + let ninput = document.getElementById("nameinput"); + if (ninput.value.length > MINIMUM_NEEDLE_LENGTH) { + if (hits.length === 0) { + validity = "bad"; + } else if (hits.length === 1 && hits[0]["exact_match"]) { + validity = "ok"; + hide("hintzone"); + } + } + ninput.setAttribute("validity", validity); }); -} \ No newline at end of file +} + +// csoport kiírása ("...az Azúrból" -- no reference of course :D), ha megkapja a szervertől +function print_from_group(group) { + group = group.trim(); + if (group === "") { + return ""; + } + + let vowels = /[aáeéiíoóöőuúüű]/i; // magánhangzók regexe + let highpitched_vowels = /[eéiíöőüű]/i; // magas hangrendű maánhangzók regexe + + // első betű megvizsgálása a névelő kiválasztásához + let b = group.charAt(0); + let article = (vowels.exec(b) != null) ? "az" : "a"; + + // hátulról az első magánhangzó keresése + let g_rev = group.split("").reverse().join(""); + let last_vowel = g_rev.match(vowels)[0]; + + // megvizsgáljuk, hogy az utolsó betű volt-e a megtalált magánhangzó + let last_letter = g_rev.charAt(0).toLowerCase(); + if (last_letter === last_vowel.charAt(0).toLowerCase()) { + if (last_letter === "a") { + last_letter = "á"; + } else if (last_letter === "e") { + last_letter = "é"; + } + + // utolsó betű kicserélése + group = group.substring(0, group.length - 1) + last_letter; + } + + // utolsó magánhangzó hangrendjének vizsgálata és rag kiválasztása + let suffix = highpitched_vowels.test(last_vowel) ? "ből" : "ból"; + + return `${article} ${group}${suffix}`; +} + +// szöveggel kitölti a nevet +function fill_name_input(str) { + document.getElementById("nameinput").value = str; +} diff --git a/js/o.js b/js/o.js new file mode 100644 index 0000000..eabb5bf --- /dev/null +++ b/js/o.js @@ -0,0 +1,25 @@ +function o(input) { + var o; + if (typeof input === "string") + o = document.getElementById(input); + else if (typeof input === "object") + o = input; + return o; +} + +// megjelenítés / eltüntetés +function show(obj) { + o(obj).setAttribute("shown", "true"); +} + +function hide(obj) { + o(obj).setAttribute("shown", "false"); +} + +function toggle_show(obj) { + o(obj).setAttribute("shown", o(obj).getAttribute("shown") === "false"); +} + +function scroll_enable(on) { + document.body.style.overflowY = on ? "scroll" : "hidden"; +} diff --git a/mkkkvv.css b/mkkkvv.css index f04313c..eb61a47 100644 --- a/mkkkvv.css +++ b/mkkkvv.css @@ -4,10 +4,14 @@ body{ --C_PRIMARY: #f89a17; --C_SEC: #44968e; --C_TER: #2a5999; + --C_OK: #67b60a; --C_TRIADIC1: #85ea11; --C_TRIADIC2: #11ea76; --C_BG1: #c0ccdf; --C_BG2: #e3ecf3; + --C_BG3: #e9f3e3; + --C_UNKNOWN: #f84c17; + --C_TEXTINPUT_COLOR: #2f4c6e; font-family: 'Faustina', serif; @@ -27,6 +31,18 @@ input[type="text"]:focus { input#nameinput { width: 100%; + color: var(--C_TEXTINPUT_COLOR); + transition: color 0.3s ease; +} + +input#nameinput[validity="ok"] { + color: var(--C_OK); + transition: color 0.3s ease; +} + +input#nameinput[validity="bad"] { + color: var(--C_UNKNOWN); + transition: color 0.3s ease; } section#hintbox { @@ -41,14 +57,35 @@ span.hit { display: block; position: static; padding: 0.2em 0.5em; + cursor: pointer; +} + +span.hit:hover { + background-color: var(--C_BG3); } span.highlight { font-weight: bold; + color: var(--C_SEC); + text-decoration: underline; } section#mainbox { display: block; position: absolute; width: min(var(--MAINBOX_WIDTH), calc(100vw - 1em)); -} \ No newline at end of file +} + +*[shown="false"] { + visibility: hidden; + display: none; + opacity: 0; + transition: 0.3s ease; + width: 0; + height: 0; +} + +*[shown="true"] { + opacity: 1; + transition: 0.3s ease; +}