diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/mkkkvv.iml b/.idea/mkkkvv.iml
new file mode 100644
index 0000000..c956989
--- /dev/null
+++ b/.idea/mkkkvv.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..648bea2
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/php.xml b/.idea/php.xml
new file mode 100644
index 0000000..0e09af4
--- /dev/null
+++ b/.idea/php.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/control_panel.php b/control_panel.php
new file mode 100644
index 0000000..01ca86f
--- /dev/null
+++ b/control_panel.php
@@ -0,0 +1,58 @@
+
+
+
+
+ MKK Közivezető-választás vezérlőpult
+
+
+
+
+
+
+
+ Közivezető-választás vezérlőpult
+
+
+
+
+
+
+ Szavazás-vezérlés
+ Szavazás megnyitása
+ Szavazás lezárása
+
+ Voksolás
+ engedélyezése
+
+ Voksolás
+ tiltása
+
+
+
+
+ Nyilvánosságra hozás
+ visszavonása
+
+
+
+ Zárt összesítés és megjelenítés
+
+
+
+
+
\ No newline at end of file
diff --git a/index.php b/index.php
index b4b845d..32e0b54 100644
--- a/index.php
+++ b/index.php
@@ -1,11 +1,19 @@
+
+
MKK Közivezető-választás
@@ -13,13 +21,36 @@
-
-
-
-
+
+ Közivezető-választás
+
-
+
+
+
+ Köszönjük, te vagy a...
+
+ ...szavazó!
+ Feltétlen nézz vissza később az eredményekért!
+
+
+
+
+
diff --git a/interface.php b/interface.php
index 2712f21..ffe1c9f 100644
--- a/interface.php
+++ b/interface.php
@@ -34,7 +34,8 @@ 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, string $group = ""): array
+function search_in_names(array $records, string $needle, string $group = "", bool $show_only_exact_match = false,
+ bool $hide_groups_of_non_duplicates = HIDE_GROUP_OF_NON_DUPLICATES): array
{
// keresés
$needle = trim($needle);
@@ -46,13 +47,18 @@ function search_in_names(array $records, string $needle, string $group = ""): ar
$exact_match = [];
$hitpos_array = [];
- $filter = function (array $var) use (&$hitpos_array, &$exact_match, $needle, $group): bool {
+ $filter = function (array $var) use (&$hitpos_array, &$exact_match, $needle, $group, $show_only_exact_match): bool {
// ha a csoporton belül keres
- if ($group !== "" && $var["group"] !== $group) {
+ if ($group !== "" && strtolower($var["group"]) !== strtolower($group)) {
return false;
}
- $hitpos = stripos($var["name"], $needle);
+ $hitpos = iconv_strpos(strtolower($var["name"]), strtolower($needle));
+
+ // pontos egyezés vizsgálata (hossz és kezdőindex vizsgálata)
+ if ($show_only_exact_match && ($hitpos != 0 || strlen($var["name"]) !== strlen($needle))) {
+ $hitpos = false;
+ }
// ha van egyezés...
if ($hitpos !== false) {
@@ -75,7 +81,7 @@ function search_in_names(array $records, string $needle, string $group = ""): ar
}
}
- if (HIDE_GROUP_OF_NON_DUPLICATES) {
+ if ($hide_groups_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"]));
@@ -113,30 +119,695 @@ function search_in_names(array $records, string $needle, string $group = ""): ar
return $filter_res;
}
+define("DATA_DIR", "data");
+define("LOGIN_ID_FILE_NAME", "electors_masked.md");
+define("VOTE_FILENAME", "votes.dat");
+define("VOTE_COUNT_FILENAME", "vote_count.dat");
+define("USED_ELECTOR_HASH_FILENAME", "electors_submitted_vote.dat");
+define("VOTE_STATE_FILENAME", "vote_state.json");
+define("VOTE_TIMESTAMP_FILENAME", "vote_timestamps.dat");
+
+function submit_name(string $name, string $group, string $elector_id)
+{
+ // default...
+ $ret = [
+ "successful" => false,
+ "index" => -1
+ ];
+
+ // ---------------
+
+ $used_hash_filename = DATA_DIR . DIRECTORY_SEPARATOR . USED_ELECTOR_HASH_FILENAME;
+ $votes_filename = DATA_DIR . DIRECTORY_SEPARATOR . VOTE_FILENAME;
+ $vote_count_filename = DATA_DIR . DIRECTORY_SEPARATOR . VOTE_COUNT_FILENAME;
+ $timestamp_filename = DATA_DIR . DIRECTORY_SEPARATOR . VOTE_TIMESTAMP_FILENAME;
+
+ // ---------------
+
+ // kölcsönös kizárás a számláló fájllal
+ $fp = fopen($vote_count_filename, "r+");
+ flock($fp, LOCK_EX); // kölcsönös kizárás
+
+ // megvizsgáljuk, hogy szavazhat-e a felhasználó
+ $used_elector_hashes = file_get_contents($used_hash_filename);
+ $elector_hash = sha1($elector_id);
+ if (strpos($used_elector_hashes, sha1($elector_id)) === false) { // ha szavazhat...
+ // személy kikeresése
+ $p = read_electable_people(ELECTABLE_PEOPLE_DATABASE);
+ $hits = search_in_names($p, $name, $group, true, false);
+
+ // ha egzakt találat van, azaz a szavazó megfelelő nevet adott meg
+ if (count($hits) === 1) {
+ // felhasználó azonosítójának beírása a felhasznált hash-ek jegyzékébe
+ copy($used_hash_filename, "$used_hash_filename.prev");
+ $hash_save_successful = file_put_contents($used_hash_filename, "$elector_hash\n", FILE_APPEND) !== false;
+
+ // szavazat mentése
+ $name = $hits[0]["name"];
+ $group = $hits[0]["group"];
+ $record = "$name//$group\n";
+ copy($votes_filename, "$votes_filename.prev");
+ $vote_save_successful = file_put_contents($votes_filename, $record, FILE_APPEND) !== false;
+
+ // időbélyeg mentése
+ copy($timestamp_filename, "$timestamp_filename.prev");
+ $timestamp = date("Y-m-d H:i:s");
+ $timestamping_successful = file_put_contents($timestamp_filename, "$timestamp\n", FILE_APPEND) !== false;
+
+ $success = $hash_save_successful && $vote_save_successful && $timestamping_successful;
+
+ if ($success) { // ha sikeres minden...
+ // szavazatszám növelése
+ $cnt = (int)(fread($fp, 255));
+ $cnt++;
+ $ret["index"] = $cnt;
+ fseek($fp, 0);
+ fwrite($fp, $cnt);
+ } else { // ha valamelyik nem sikerül, akkor visszaállunk a korábbi állapotba
+ rename($used_hash_filename, "$used_hash_filename.err_" . time()); // hibás fájl eltárolása
+ rename($votes_filename, "$votes_filename.err_" . time());
+ rename($timestamp_filename, "$timestamp_filename.err_" . time());
+ copy("$used_hash_filename.prev", $used_hash_filename); // régi állapot visszaállítása
+ copy("$votes_filename.prev", $votes_filename);
+ copy("$timestamp_filename.prev", $timestamp_filename);
+ }
+
+ $ret["successful"] = $success;
+ }
+ }
+
+ fclose($fp); // lock elengedése és fájl bezárása
+
+ return $ret;
+}
+
+// név és csoport szétválasztása (NEM UGYANAZ, MINT JS-ben!)
+function fetch_name_and_group(string $compound): array
+{
+ $parts = explode("//", $compound);
+ return ["name" => $parts[0], "group" => $parts[1]];
+}
+
+// állapotfájl előállítása, ha nem létezik
+function load_state()
+{
+ $vote_state_fname = DATA_DIR . DIRECTORY_SEPARATOR . VOTE_STATE_FILENAME;
+ $state = [];
+ if (!file_exists($vote_state_fname)) {
+ $state = [
+ "state" => "closed",
+ "open_for_submit" => false,
+ "auto_manage" => false,
+ "open_date" => "2022-08-01 08:00:00",
+ "close_date" => "2022-08-01 20:00:00",
+ "results_public" => false,
+ "public_results_plot_filename" => "",
+ "public_results_plot_filename_mobile" => ""
+ ];
+ } else {
+ $state = json_decode(file_get_contents($vote_state_fname), true);
+ }
+
+ return $state;
+}
+
+function save_state($state)
+{
+ file_put_contents(DATA_DIR . DIRECTORY_SEPARATOR . VOTE_STATE_FILENAME, json_encode($state, JSON_PRETTY_PRINT));
+}
+
+// jelentés generálása
+function generate_report($omit_votes = true)
+{
+ $state = load_state();
+ $elector_hashes = explode("\n", file_get_contents(DATA_DIR . DIRECTORY_SEPARATOR . LOGIN_ID_FILE_NAME));
+ $total_elector_count = 0;
+ foreach ($elector_hashes as $elector_hash) {
+ if (trim($elector_hash) !== "") {
+ $total_elector_count++;
+ }
+ }
+
+ $vote_list_str = file_get_contents(DATA_DIR . DIRECTORY_SEPARATOR . VOTE_FILENAME);
+ $vote_list = explode("\n", $vote_list_str);
+ $votes_grouped = [];
+ $total_votes = 0;
+ foreach ($vote_list as $vote) {
+ // üres sorok kihagyása
+ if (strlen(trim($vote)) === 0) {
+ continue;
+ }
+
+ $votes_grouped[$vote] = (($votes_grouped[$vote]) ?? 0) + 1;
+ $total_votes++;
+ }
+
+ // rendezés szavazatok száma alapján
+ uasort($votes_grouped, fn($a, $b) => ($b - $a));
+
+ // név és csoport szétválasztása
+ $votes_structured = [];
+ foreach ($votes_grouped as $id_compound => $vote_cnt) {
+ $expl_vote = fetch_name_and_group($id_compound);
+ $votes_structured[$expl_vote["name"]] = ["name" => $expl_vote["name"], "group" => $expl_vote["group"], "count" => $vote_cnt, "ratio" => ($vote_cnt / $total_votes)];
+ }
+
+ $report = [
+ "total_votes" => $total_votes,
+ "total_electors" => $total_elector_count,
+ "state" => $state
+ ];
+
+ if (!$omit_votes) {
+ $report["records"] = array_values($votes_structured);
+ }
+
+ return $report;
+}
+
+function RGBToHSLV($r, $g, $b, bool $hsv = false)
+{
+ $r /= 255;
+ $g /= 255;
+ $b /= 255;
+
+ $x_max = max($r, $g, $b);
+ $x_min = min($r, $g, $b);
+ $c = $x_max - $x_min;
+
+ $l = ($x_max + $x_min) / 2;
+
+ $h = 0;
+ if ($c === 0) {
+ $h = 0;
+ } else if ($x_max === $r) {
+ $h = 60 * ($g - $b) / $c;
+ } else if ($x_max === $g) {
+ $h = 60 * (2 + ($b - $r) / $c);
+ } else if ($x_max === $b) {
+ $h = 60 * (4 + ($r - $g) / $c);
+ }
+
+ if ($hsv) {
+ $s = (($x_max === 0)) ? 0 : ((float)$c / $x_max);
+ return [$h, $s, $x_max];
+ } else {
+ $s = (($l === 0) || ($l === 1)) ? 0 : (2 * ($x_max - $l) / (1 - abs(2 * $l - 1)));
+ return [$h, $s, $l];
+ }
+
+}
+
+function HSVtoRGB($h, $s, $v)
+{
+ $c = $v * $s;
+ $h_ = $h / 60;
+ $x = $c * (1 - abs(fmod($h_, 2) - 1));
+
+ $rgb1 = [0, 0, 0];
+ if ($h_ >= 0 && $h_ < 1) {
+ $rgb1 = [$c, $x, 0];
+ } else if ($h_ >= 1 && $h_ < 2) {
+ $rgb1 = [$x, $c, 0];
+ } else if ($h_ >= 2 && $h_ < 3) {
+ $rgb1 = [0, $c, $x];
+ } else if ($h_ >= 3 && $h_ < 4) {
+ $rgb1 = [0, $x, $c];
+ } else if ($h_ >= 4 && $h_ < 5) {
+ $rgb1 = [$x, 0, $c];
+ } else if ($h_ >= 5 && $h_ < 6) {
+ $rgb1 = [$c, 0, $x];
+ }
+
+ $m = $v - $c;
+ $rgb = [$rgb1[0] + $m, $rgb1[1] + $m, $rgb1[2] + $m];
+
+ return $rgb;
+}
+
+function RGBtoHex($r, $g, $b)
+{
+ $r_str = dechex($r);
+ $g_str = dechex($g);
+ $b_str = dechex($b);
+
+ $r_str = (strlen($r_str) === 1) ? "0$r_str" : $r_str;
+ $g_str = (strlen($g_str) === 1) ? "0$g_str" : $g_str;
+ $b_str = (strlen($b_str) === 1) ? "0$b_str" : $b_str;
+
+ return "#$r_str$g_str$b_str";
+}
+
+//function RGBtoHCL($r, $g, $b)
+//{
+//
+//}
+
+define("SVG_REPORT_WIDTH", 700);
+define("SVG_REPORT_HEIGHT", 350);
+define("SVG_REPORT_STROKE_WIDTH", 30);
+define("SVG_REPORT_LEGEND_MARK_SIZE", 20);
+define("SVG_REPORT_HIGHLIGHT_STROKE_WIDTH", 40);
+define("SVG_REPORT_PLOT_THRESHOLD_PERCENT", 5);
+define("SVG_REPORT_LEGEND_FONT_SIZE", 20);
+define("SVG_REPORT_START_COLOR", "003F5C");
+define("SVG_REPORT_END_COLOR", "F89A17");
+define("SVG_REPORT_PIE_RADIUS", 110);
+define("SVG_REPORT_ANIMATION_DUR", 2);
+
+// SVG-kép generálása a jelentésből
+function generate_svg_plot($report, $mobile = false): string
+{
+ $pie_orig = [SVG_REPORT_WIDTH / 2, SVG_REPORT_HEIGHT / 2];
+ $pie_radius = SVG_REPORT_PIE_RADIUS;
+ $cum_percent = 0;
+ $legend_font_size = SVG_REPORT_LEGEND_FONT_SIZE;
+
+ $last_segment_midpoint = [0, 0];
+ $last_segment_midpoint_angle = 0;
+
+ // százalékértéknyi körív rajzolása
+ $svg_curve = function ($percent) use (&$cum_percent, $pie_radius, $pie_orig, &$last_segment_midpoint, &$last_segment_midpoint_angle) {
+ $x_rot = $cum_percent / 100.0 * 360; // x-tengely forgatása
+
+ $start_angle = -$cum_percent / 100.0 * 2 * M_PI; // radián
+ $end_angle = -($cum_percent + $percent) / 100.0 * 2 * M_PI; // radián
+ $middle_point_angle = -($cum_percent + $percent / 2); // fok
+
+ $start_x = $pie_orig[0] + cos($start_angle) * $pie_radius;
+ $start_y = $pie_orig[1] + sin($start_angle) * $pie_radius;
+
+ $end_x = $pie_orig[0] + cos($end_angle) * $pie_radius;
+ $end_y = $pie_orig[1] + sin($end_angle) * $pie_radius;
+
+ $last_segment_midpoint[0] = $pie_orig[0] + cos($middle_point_angle / 100.0 * 2 * M_PI) * $pie_radius;
+ $last_segment_midpoint[1] = $pie_orig[1] + sin($middle_point_angle / 100.0 * 2 * M_PI) * $pie_radius;
+ $last_segment_midpoint_angle = $middle_point_angle * 3.6;
+
+ $cum_percent += $percent;
+ return "M $start_x $start_y
+ A $pie_radius $pie_radius $x_rot 0 0 $end_x $end_y\n";
+ };
+
+ // kurzor mozgatása
+ $svg_move_cursor = function ($x, $y) {
+ return "M $x $y\n";
+ };
+
+ // útvonal generálása
+ $svg_path = function ($d, $color, $id, $class = "sector", $stroke_width = SVG_REPORT_STROKE_WIDTH) {
+ return "\n";
+ };
+
+ // jelmagyarázat generálása
+ $svg_legend = function ($color, $text, $x, $y, $mark_size = SVG_REPORT_LEGEND_MARK_SIZE) use ($legend_font_size, $pie_orig, $mobile) {
+ $rect_x = $x;
+ $rect_y = $y;
+ $circ_radius = $mark_size / 2;
+ $anchor_cond = ($x > $pie_orig[0] || $mobile);
+ $text_x_offset_sign = $anchor_cond ? 1 : -1;
+ $text_anchor = $anchor_cond ? "start" : "end";
+ $text_x = $x + $text_x_offset_sign * ($circ_radius + 0.5 * $legend_font_size);
+ $text_y = $y; // + ($mark_size - 0.4 * $legend_font_size) / 2;
+
+ //return "
+ return "
+ $text\n";
+ };
+
+ // színpaletta előállítása
+ $generate_palette = function ($start_hex, $end_hex, $cnt): array {
+ if (gettype($start_hex) === "string") {
+ $start_hex = hexdec($start_hex);
+ }
+ if (gettype($end_hex) === "string") {
+ $end_hex = hexdec($end_hex);
+ }
+
+ // szétválasztás komponensekre
+ $start_rgb = [($start_hex & 0xFF0000) >> 16, ($start_hex & 0x00FF00) >> 8, ($start_hex & 0x0000FF)];
+ $end_rgb = [($end_hex & 0xFF0000) >> 16, ($end_hex & 0x00FF00) >> 8, ($end_hex & 0x0000FF)];
+
+ $start_hsv = RGBToHSLV($start_rgb[0], $start_rgb[1], $start_rgb[2], true);
+ $end_hsv = RGBToHSLV($end_rgb[0], $end_rgb[1], $end_rgb[2], true);
+
+ // mindig a hosszabb görbe választása
+ $hue_diff = $end_hsv[0] - $start_hsv[0];
+ if (abs($hue_diff) < 180) {
+ $start_hsv[0] -= 360;
+ }
+
+ // interpoláció
+ $step = [($end_hsv[0] - $start_hsv[0]) / ($cnt - 1),
+ ($end_hsv[1] - $start_hsv[1]) / ($cnt - 1),
+ ($end_hsv[2] - $start_hsv[2]) / ($cnt - 1)];
+
+ $palette = [];
+ for ($i = 0; $i < $cnt; $i++) {
+ $hue = $start_hsv[0] + $step[0] * $i % 360;
+ $hue += ($hue < 0) ? 360 : 0;
+ $color = [$hue, $start_hsv[1] + $step[1] * $i, $start_hsv[2] + $step[2] * $i];
+ $color_rgb = HSVtoRGB($color[0], $color[1], $color[2]);
+ //$palette[] = "hsl(" . (floor($color[0])) . "," . (floor($color[1])) . "%," . (floor($color[2])) . "%)";
+ //$palette[] = "rgb(" . (round($color_rgb[0] * 255)) . "," . (round($color_rgb[1] * 255)) . "," . (round($color_rgb[2] * 255)) . ")";
+ $palette[] = RGBtoHex((round($color_rgb[0] * 255)), (round($color_rgb[1] * 255)), (round($color_rgb[2] * 255)));
+ }
+
+ return $palette;
+ };
+
+ // -------------------
+
+ // küszöbérték feletti blokkok számának meghatározása
+ $sector_count = 0;
+ foreach ($report["records"] as $record) {
+ $sector_count++;
+ if ($record["ratio"] * 100.0 < SVG_REPORT_PLOT_THRESHOLD_PERCENT) {
+ break;
+ }
+ }
+
+ // színpaletta előállítása
+ $palette = $generate_palette(SVG_REPORT_START_COLOR, SVG_REPORT_END_COLOR, $sector_count);
+ //$palette = [ "#003f5c", "#424d83", "#8e5092", "#d24f81", "#fa6756", "#f89a17" ];
+
+ // svg-kép előállítása
+ $svg = "";
+
+ // stíluslap hozzáadása
+ $hlsw = SVG_REPORT_HIGHLIGHT_STROKE_WIDTH;
+ $animdur = SVG_REPORT_ANIMATION_DUR;
+ $svg .= "";
+
+ $total = $report["total_votes"];
+ $last_legend_anchor = [];
+ foreach ($report["records"] as $idx => $record) {
+ // kördiagram cikkei
+ $percent = $record["count"] * 100.0 / $total;
+ $joined_sector = $percent < SVG_REPORT_PLOT_THRESHOLD_PERCENT; // az küszöbérték alatti szavaztokat egybe gyűjtjük
+ if ($joined_sector) {
+ $percent = 100.0 - $cum_percent; // az összes maradék helyet kitöltjük
+ }
+
+ //$color = "rgb(" . random_int(0, 255) . "," . random_int(0, 255) . "," . random_int(0, 255) . ")";
+ $color = $palette[$idx];
+
+ $anim_delay = SVG_REPORT_ANIMATION_DUR * 2/3 * ($sector_count - $idx - 1);
+ $svg .= "";
+ $sector_id = "sector$idx";
+ $svg .= $svg_path($svg_curve($percent), $color, "$sector_id"); // körcikk
+ $svg .= "" // szöveg rajta
+ . number_format((float)$percent, 1, ',', '') .
+ "%\n";
+
+ // jelmagyarázat
+ $legend_anchor = [];
+ if (!$mobile) { // normál megjelenítés
+ $legend_anchor = $pie_orig;
+ $legend_anchor[0] += ($last_segment_midpoint[0] - $pie_orig[0]) * (1 + 1.2 * SVG_REPORT_STROKE_WIDTH / $pie_radius);
+ $legend_anchor[1] += ($last_segment_midpoint[1] - $pie_orig[1]) * (1 + 1.2 * SVG_REPORT_STROKE_WIDTH / $pie_radius);
+ } else { // mobilos megjelenítés
+ $legend_anchor[0] = $pie_orig[0] - SVG_REPORT_PIE_RADIUS;
+ $legend_anchor[1] = $pie_orig[1] + SVG_REPORT_PIE_RADIUS + SVG_REPORT_HIGHLIGHT_STROKE_WIDTH * 1.5 + 1.5 * $legend_font_size * $idx;
+ }
+
+ if (!$joined_sector) {
+ $legend_text = "${record['name']} (${record['count']})";
+ } else {
+ $legend_text = "Többiek";
+ }
+ $svg .= $svg_legend($color, $legend_text, $legend_anchor[0], $legend_anchor[1]);
+ $svg .= "";
+
+ $last_legend_anchor = $legend_anchor;
+
+ if ($joined_sector) {
+ break;
+ }
+ }
+
+ // viewBox beállítása
+ $viewBox = [];
+ if (!$mobile) { // asztali kép
+ $viewBox = "0 0 " . SVG_REPORT_WIDTH . " " . SVG_REPORT_HEIGHT;
+ $style = "style='width: " . SVG_REPORT_WIDTH . "px;'";
+ } else { // mobilos kép
+ $vBx = SVG_REPORT_WIDTH / 2 - (SVG_REPORT_PIE_RADIUS + SVG_REPORT_HIGHLIGHT_STROKE_WIDTH + 1);
+ $vBy = SVG_REPORT_HEIGHT / 2 - (SVG_REPORT_PIE_RADIUS + SVG_REPORT_HIGHLIGHT_STROKE_WIDTH + 1);
+ $vBw = (SVG_REPORT_PIE_RADIUS + SVG_REPORT_HIGHLIGHT_STROKE_WIDTH) * 2;
+ $vBh = $last_legend_anchor[1] + 2 * $legend_font_size;
+ $viewBox = "$vBx $vBy $vBw $vBh";
+ $style = "";
+ }
+
+ $svg = "";
+
+ return $svg;
+}
+
+// azonosító ellenőrzése
+function verify_id($id)
+{
+ if (trim($id) === "") {
+ return ["valid" => false, "used" => false];
+ }
+ $ids = file_get_contents(DATA_DIR . DIRECTORY_SEPARATOR . LOGIN_ID_FILE_NAME);
+ $used_hashes = file_get_contents(DATA_DIR . DIRECTORY_SEPARATOR . USED_ELECTOR_HASH_FILENAME);
+ $needle = sha1($id) . "\n"; // teljes sort kersünk, mert különben elég lenne egy részét ismerni az adatnak
+ $id_valid = strpos($ids, $needle) !== false;
+ $id_used = strpos($used_hashes, $needle) !== false;
+ return ["valid" => $id_valid, "used" => $id_used];
+}
+
// --------------------------------
-define("ELECTABLE_PEOPLE_DATABASE", "data/electable_people_test.md");
+define("CP_LOGIN_ID_FILENAME", "cp_login_hashes.dat");
+
+// Vezérlőpult kezelése
+
+// bejelentkezés a vezérlőpultba
+function cp_verify_id($id)
+{
+ if (trim($id) === "") {
+ return false;
+ }
+ $ids = file_get_contents(DATA_DIR . DIRECTORY_SEPARATOR . CP_LOGIN_ID_FILENAME);
+ return strpos($ids, sha1($id) . "\n") !== false;
+}
+
+define("STATE_LOCK_FILENAME", "state.lock");
+define("PUBLIC_DIR", "public");
+define("FULL_RESULT_RECORDS_FILENAME", "full_results.json");
+
+// szavazásállapot módosítása
+function cp_modify_state($command)
+{
+ $fp = fopen(DATA_DIR . DIRECTORY_SEPARATOR . STATE_LOCK_FILENAME, "w");
+ flock($fp, LOCK_EX);
+
+ $state = load_state();
+ switch ($command) {
+ case "open_election":
+ $state["state"] = "open";
+ break;
+ case "close_election":
+ $state["state"] = "closed";
+ break;
+ case "enable_submitting":
+ $state["open_for_submit"] = true;
+ break;
+ case "disable_submitting":
+ $state["open_for_submit"] = false;
+ break;
+ case "publish_results":
+ {
+ // grafikon rajzolása
+ $state["results_public"] = true;
+ $uniqid = uniqid();
+ $plot_filename_normal = PUBLIC_DIR . DIRECTORY_SEPARATOR . "results_$uniqid.svg";
+ $plot_filename_mobile = PUBLIC_DIR . DIRECTORY_SEPARATOR . "m_results_$uniqid.svg";
+ $report = generate_report(false);
+ $svg_normal = generate_svg_plot($report);
+ file_put_contents($plot_filename_normal, $svg_normal);
+ $svg_mobile = generate_svg_plot($report, true);
+ file_put_contents($plot_filename_mobile, $svg_mobile);
+ $state["public_results_plot_filename"] = $plot_filename_normal;
+ $state["public_results_plot_filename_mobile"] = $plot_filename_mobile;
+
+ // szavazat-eredmények mentése
+ $records_without_group = [];
+ foreach ($report["records"] as $record) { // csoport törlése (privacy and like that)
+ $records_without_group[] = [ "name" => $record["name"], "count" => $record["count"], "ratio" => $record["ratio"] ];
+ }
+ file_put_contents(PUBLIC_DIR . DIRECTORY_SEPARATOR . FULL_RESULT_RECORDS_FILENAME, json_encode($records_without_group));
+ }
+ break;
+ case "unpublish_results":
+ $state["results_public"] = false;
+ unlink($state["public_results_plot_filename"]);
+ unlink($state["public_results_plot_filename_mobile"]);
+ $state["public_results_plot_filename"] = "";
+ $state["public_results_plot_filename_mobile"] = "";
+ break;
+ }
+ save_state($state);
+
+ fclose($fp);
+
+ return $state;
+}
+
+
+// --------------------------------
+
+define("ELECTABLE_PEOPLE_DATABASE", "data/electable_people.md");
$action = json_decode($_POST["action"]) ?? "none";
+$req_data = json_decode($_POST["data"] ?? "[]", true);
$res = "";
+$disable_jsoning = false;
+// Belépés nélküli feldolgozás, ha nem sikerül, akkor processed = false;
+$processed = true;
switch ($action) {
- case "search":
+ case "login":
{
- $needle = json_decode($_POST["needle"]);
- $group = json_decode($_POST["group"]);
- $p = read_electable_people(ELECTABLE_PEOPLE_DATABASE);
- $hits = search_in_names($p, $needle, $group);
- $res = $hits;
+ $elector_id = $req_data["elector_id"] ?? "";
+ $res = verify_id($elector_id);
+ if ($res["valid"]) {
+ $state = load_state();
+ $res["open"] = $state["state"] === "open";
+ if ($res["open"]) {
+ $res["open_for_submit"] = $state["open_for_submit"];
+ $res["results_public"] = $state["results_public"];
+ }
+ } else if(cp_verify_id($elector_id)) { // megnézzük, hogy admin-e, ha igen, akkor a szavazás indítása előtt beléphet
+ $res["valid"] = true;
+ $res["used"] = false;
+ $state = load_state();
+ $res["open"] = $state["state"] === "open";
+ $res["open_for_submit"] = true;
+ $res["results_public"] = false;
+ }
}
break;
- case "none":
+ case "cp_login":
+ {
+ $cp_id = $req_data["cp_id"] ?? "";
+ $res = cp_verify_id($cp_id);
+ }
+ break;
+ default:
+ $processed = false;
break;
}
-echo json_encode($res);
+// ha feldolgozta, akkor ugrás a végére (inkább a goto, mint 46 zárójel... :D)
+if ($processed) {
+ goto exit_point; // --->
+}
-//$p = read_electable_people("data/electable_people_test.md");
+// Belépéses (azonosítóhoz kötött) feldolgozás
+$elector_id = json_decode($_POST["elector_id"] ?? "");
+$state = load_state();
+$admin_login = cp_verify_id($elector_id);
+if (((verify_id($elector_id)["valid"]) || $admin_login) && $state["state"] === "open") {
+ $processed = true;
+ switch ($action) {
+ case "search":
+ {
+ if (!$state["open_for_submit"] && !$admin_login) {
+ break;
+ }
-return;
\ No newline at end of file
+ $needle = $req_data["needle"] ?? "";
+ $group = $req_data["group"] ?? "";
+ $p = read_electable_people(ELECTABLE_PEOPLE_DATABASE);
+ $hits = search_in_names($p, $needle, $group);
+ $res = $hits;
+ }
+ break;
+ case "submit":
+ {
+ if (!$state["open_for_submit"] && !$admin_login) {
+ break;
+ }
+
+ $name = $req_data["needle"] ?? "";
+ $group = $req_data["group"] ?? "";
+ $res = submit_name($name, $group, $elector_id);
+ }
+ break;
+ case "results":
+ {
+ $mobile = $req_data["mobile"] ?? false;
+ $state = load_state();
+ $res = ["available" => $state["results_public"]];
+ if ($state["results_public"]) {
+ $res["plot_url"] = $mobile ? $state["public_results_plot_filename_mobile"] : $state["public_results_plot_filename"];
+ $res["details"] = json_decode(file_get_contents(PUBLIC_DIR . DIRECTORY_SEPARATOR . FULL_RESULT_RECORDS_FILENAME), true);
+ }
+ }
+ break;
+ case "none":
+ break;
+ default:
+ $processed = false;
+ break;
+ }
+}
+
+if ($processed) {
+ goto exit_point;
+}
+
+// Control panel parancsok
+$processed = true;
+$elector_id = json_decode($_POST["cp_id"] ?? "");
+if (cp_verify_id($elector_id)) {
+ switch ($action) {
+ case "cp_short_info":
+ {
+ $res = generate_report(true); // az összesített szavazatokat hagyja ki!
+ }
+ break;
+ case "cp_mod_state":
+ {
+ $command = $req_data["command"];
+ $res = cp_modify_state($command);
+ }
+ break;
+ case "cp_generate_plot":
+ {
+ $disable_jsoning = true;
+ $res = generate_svg_plot(generate_report(false));
+ }
+ break;
+ default:
+ $processed = false;
+ break;
+ }
+}
+
+exit_point:
+echo $disable_jsoning ? $res : json_encode($res);
+
+//$p = read_electable_people("data/electable_people.md");
+
+return;
diff --git a/js/mkkkvv.js b/js/mkkkvv.js
index c961507..088c8c4 100644
--- a/js/mkkkvv.js
+++ b/js/mkkkvv.js
@@ -1,31 +1,42 @@
const MINIMUM_NEEDLE_LENGTH = 3;
+function fetch_name_and_group(needle) {
+ let ret = {
+ needle: "",
+ group: ""
+ };
+ let group_regex = /(\[[a-záéíóöúü]+\]$)/gi;
+ let group_extracted = needle.match(group_regex);
+ if (group_extracted != null) {
+ ret["group"] = group_extracted[0].substring(1, group_extracted[0].length - 1);
+ ret["needle"] = needle.substring(0, needle.length - group_extracted[0].length - 1).trim();
+ } else {
+ ret["needle"] = needle;
+ }
+ return ret;
+}
+
+let ELECTOR_ID;
+
// keresés indítása a nevek között
-function search_in_names(needle) {
+function search_in_names() {
let hintbox = document.getElementById("hintbox");
+ let needle = document.getElementById("nameinput").value;
if (needle.trim().length < MINIMUM_NEEDLE_LENGTH) {
hintbox.innerHTML = "";
- hide("hintzone");
+ collapse("hintzone");
+ collapse("submitbtn");
+ stop_submit_caption_generator();
o("nameinput").setAttribute("validity", "");
return;
}
- let request_data = {
- action: "search",
- 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;
- }
+ let request_data = {};
+ request_data["data"] = fetch_name_and_group(needle);
+ request_data["action"] = "search";
+ request_data["elector_id"] = ELECTOR_ID;
request(request_data).then(resp => {
hintbox.innerHTML = "";
@@ -40,8 +51,10 @@ function search_in_names(needle) {
hit.addEventListener("click", () => {
let group_id = val["duplicate"] ? ` [${val["group"]}]` : "";
fill_name_input(`${val["name"]}${group_id}`);
- hide("hintzone");
+ collapse("hintzone");
ninput.setAttribute("validity", "ok");
+ expand("submitbtn");
+ start_submit_caption_generator();
});
let name_node = document.createElement("span");
@@ -79,7 +92,7 @@ function search_in_names(needle) {
});
// doboz megjelenítése, ha szükséges
- hits.length > 0 ? show("hintzone") : hide("hintzone");
+ hits.length > 0 ? expand("hintzone") : collapse("hintzone");
// szövegmező színezése
let validity = "";
@@ -87,9 +100,17 @@ function search_in_names(needle) {
if (ninput.value.length > MINIMUM_NEEDLE_LENGTH) {
if (hits.length === 0) {
validity = "bad";
+ collapse("submitbtn");
+ stop_submit_caption_generator();
} else if (hits.length === 1 && hits[0]["exact_match"]) {
validity = "ok";
- hide("hintzone");
+ collapse("hintzone");
+ expand("submitbtn");
+ start_submit_caption_generator();
+ } else {
+ expand("hintzone");
+ collapse("submitbtn");
+ stop_submit_caption_generator();
}
}
ninput.setAttribute("validity", validity);
@@ -137,3 +158,171 @@ function print_from_group(group) {
function fill_name_input(str) {
document.getElementById("nameinput").value = str;
}
+
+const ARROWS = [/*"→",*/ "↠", "↣", "↦", "↬", "⇉",
+ /*"⇒",*/ "⇛", "⇝"];
+
+const SUBMIT_CAPTION_PREFIX = "Mehet! ";
+
+function generate_new_caption() {
+ document.getElementById("submitbtn").innerHTML = SUBMIT_CAPTION_PREFIX +
+ ARROWS[Math.floor(Math.random() * (ARROWS.length))];
+}
+
+CAPTION_TIMER = -1;
+
+function start_submit_caption_generator() {
+ if (CAPTION_TIMER === -1) {
+ generate_new_caption();
+ CAPTION_TIMER = setInterval(() => {
+ generate_new_caption();
+ }, 1000);
+ }
+}
+
+function stop_submit_caption_generator() {
+ if (CAPTION_TIMER !== -1) {
+ clearInterval(CAPTION_TIMER);
+ CAPTION_TIMER = -1;
+ }
+}
+
+function submit_name() {
+ stop_submit_caption_generator();
+ let submitbtn = document.getElementById("submitbtn");
+ submitbtn.innerText = "Már megy is!...";
+
+ needle = document.getElementById("nameinput").value;
+
+ // csoport és név szétválasztása
+ let request_data = {};
+ request_data["data"] = fetch_name_and_group(needle);
+ request_data["action"] = "submit";
+ request_data["elector_id"] = ELECTOR_ID;
+
+ request(request_data).then(resp_str => {
+ let resp = JSON.parse(resp_str);
+ console.log(resp);
+ if (resp["successful"]) {
+ hide("mainbox");
+ show("thankbox");
+ o("elector_index").innerText = `${resp["index"]}.`;
+ } else {
+ submitbtn.innerText = "Hiba, próbáld meg újra!";
+ }
+ });
+}
+
+function login() {
+ let id_str = document.getElementById("idinput").value;
+
+ if (id_str.trim().length === 0) {
+ return;
+ }
+
+ if (login.login_in_progress === undefined) {
+ login.login_in_progress = true;
+ } else if (login.login_in_progress) {
+ return;
+ }
+
+ let request_data = {
+ action: "login",
+ data: {
+ elector_id: id_str
+ }
+ }
+
+ let loginbtn = document.getElementById("loginbtn");
+ loginbtn.innerText = "Türelem...";
+
+ request(request_data).then(resp_str => {
+ let resp = JSON.parse(resp_str);
+ if (resp["valid"]) {
+ ELECTOR_ID = id_str; // így nem kell süti...
+ loginbtn.innerText = "Sikeres! :)";
+ hide("loginbox");
+ if (resp["open"]) {
+ if (resp["results_public"]) { // eredmények publikálva vannak
+ show("resultbox");
+ load_results();
+ } else if (resp["open_for_submit"] && !resp["used"]) { // nem publikusak az eredmények, lehet szavazni és még nem szavazott
+ show("mainbox");
+ } else if (resp["open_for_submit"] && resp["used"]) { // nem publikusak az eredmények, lehet szavazni és de már szavazott
+ show("infobox");
+ o("infoheader").innerText = "Már szavaztál. Az eredmények még nem elérhetők, de mi is kíváncsian várjuk őket! :)";
+ } else { // nem publikusak az eredmények, nem lehet szavazni
+ show("infobox");
+ o("infoheader").innerText = "Még vagy már nem lehet szavazatot leadni!";
+ }
+ } else {
+ show("infobox");
+ o("infoheader").innerText = "A szavazófelület még vagy már nem elérhető, nézz vissza később!";
+ }
+ } else {
+ loginbtn.innerText = "Megpróbálom újra!";
+ }
+ login.login_in_progress = false;
+ }
+ )
+ ;
+}
+
+function load_results() {
+ let request_data = {
+ action: "results",
+ elector_id: ELECTOR_ID,
+ data: {
+ mobile: MOBILE
+ }
+ }
+
+ request(request_data).then(resp_str => {
+ let resbox = document.getElementById("resultbox");
+ let resp = JSON.parse(resp_str);
+ if (resp["available"]) {
+ let pie_plot_url = resp["plot_url"];
+ let details = resp["details"];
+ let headline = `Eredmények
`
+ resbox.innerHTML = headline + `
`;
+
+ // grafikon betöltése
+ let load_pie_req = new XMLHttpRequest();
+ load_pie_req.addEventListener("load", () => {
+ let str = headline + load_pie_req.response;
+ str += `Teljes összesítés:
`
+ let total_count = 0;
+ for (let i = 0; i < details.length; i++) {
+ let rec = details[i];
+ total_count += rec["count"];
+ let percent = (rec["ratio"] * 100).toFixed(1);
+ str += `${i+1}. ${rec["name"]} (${percent}%, ${rec["count"]} szavazat)
`;
+ }
+ str += "
";
+ str += `...összesen ${total_count} szavazat alapján! Gratulálunk! :)`
+ resbox.innerHTML = str;
+
+ o("full_records").style.animationDelay = o("datagroup0").style.animationDelay;
+ });
+ load_pie_req.open("GET", pie_plot_url);
+ load_pie_req.send();
+
+ } else {
+ //resbox.innerHTML = `Még nem elérhetők az eredmények, de mi is kíváncsian várjuk! :)
`
+ }
+ })
+}
+
+// #003f5c
+// #444e86
+// #955196
+// #dd5182
+// #ff6e54
+// #ffa600
+
+// #003f5c
+// #424d83
+// #8e5092
+// #d24f81
+// #fa6756
+// #f89a17
\ No newline at end of file
diff --git a/js/mkkkvv_cp.js b/js/mkkkvv_cp.js
new file mode 100644
index 0000000..1bb6d34
--- /dev/null
+++ b/js/mkkkvv_cp.js
@@ -0,0 +1,114 @@
+let CP_ID = "";
+
+function cp_login() {
+ let cp_id = document.getElementById("cpidinput").value.trim();
+ if (cp_id.length === 0) {
+ return;
+ }
+
+ let request_data = {
+ action: "cp_login",
+ data: {
+ cp_id: cp_id
+ }
+ }
+ request(request_data).then(resp_str => {
+ let resp = JSON.parse(resp_str);
+ if (resp) {
+ CP_ID = cp_id;
+ cp_report(); // információk letöltése
+ show("control_panel");
+ hide("loginbox");
+ }
+ });
+}
+
+function cp_report() {
+ let request_data = {
+ action: "cp_short_info",
+ cp_id: CP_ID,
+ }
+ request(request_data).then(resp_str => {
+ // alapinfók kiírása
+ let report = JSON.parse(resp_str);
+ let short_info = `Összefoglaló információk
+ Szavazatok: ${report["total_votes"]}/${report["total_electors"]}
`;
+ document.getElementById("short_info").innerHTML = short_info;
+
+ // gombok láthatóságának vezérlése
+ cp_refresh_control_buttons(report["state"]);
+ });
+}
+
+function cp_toggle_publish_results(en) {
+ if (en) {
+ show("publishbtn");
+ } else {
+ hide("publishbtn");
+ }
+}
+
+function cp_refresh_control_buttons(state) {
+ if (state["open_for_submit"]) {
+ hide("enablesubmitbtn");
+ show("disablesubmitbtn");
+ } else {
+ show("enablesubmitbtn");
+ hide("disablesubmitbtn");
+ }
+
+ if (state["state"] === "open") {
+ hide("openelectionbtn");
+ show("closeelectionbtn");
+ show("submitbox");
+ } else if (state["state"] === "closed") {
+ show("openelectionbtn");
+ hide("closeelectionbtn");
+ hide("submitbox");
+ }
+
+ if (state["results_public"]) {
+ show("undopublishbtn");
+ hide("publishbox");
+ } else {
+ hide("undopublishbtn");
+ show("publishbox");
+ }
+
+ if (state["results_public"]) {
+ show("undopublishbtn");
+ hide("publishbox");
+ } else {
+ hide("undopublishbtn");
+ show("publishbox");
+ }
+}
+
+function cp_modify_state(cmd) {
+ let request_data = {
+ action: "cp_mod_state",
+ cp_id: CP_ID,
+ data: {
+ command: cmd
+ }
+ };
+
+ request(request_data).then(resp_str => {
+ let state = JSON.parse(resp_str);
+ cp_refresh_control_buttons(state);
+ });
+}
+
+function cp_internal_totaling(filename) {
+ let request_data = {
+ action: "cp_generate_plot",
+ cp_id: CP_ID
+ };
+
+ request(request_data).then(svg => {
+ let plotTab = window.open("newtab");
+ plotTab.addEventListener("load", () => {
+ plotTab.document.write(svg);
+ });
+ });
+}
\ No newline at end of file
diff --git a/js/o.js b/js/o.js
index eabb5bf..d42695e 100644
--- a/js/o.js
+++ b/js/o.js
@@ -23,3 +23,15 @@ function toggle_show(obj) {
function scroll_enable(on) {
document.body.style.overflowY = on ? "scroll" : "hidden";
}
+
+function collapse(obj) {
+ o(obj).setAttribute("collapsed", "true");
+}
+
+function expand(obj) {
+ o(obj).setAttribute("collapsed", "false");
+}
+
+function toggle_collapse(obj) {
+ o(obj).setAttribute("collapsed", o(obj).getAttribute("collapsed") === "false");
+}
\ No newline at end of file
diff --git a/media/arrow.svg b/media/arrow.svg
new file mode 100644
index 0000000..4bd4d16
--- /dev/null
+++ b/media/arrow.svg
@@ -0,0 +1,78 @@
+
+
+
+
diff --git a/media/spinner.svg b/media/spinner.svg
new file mode 100644
index 0000000..efbae43
--- /dev/null
+++ b/media/spinner.svg
@@ -0,0 +1,7 @@
+
diff --git a/mkkkvv.css b/mkkkvv.css
index eb61a47..bca8469 100644
--- a/mkkkvv.css
+++ b/mkkkvv.css
@@ -1,15 +1,17 @@
@import url('https://fonts.googleapis.com/css2?family=Faustina&display=swap');
-body{
+body {
--C_PRIMARY: #f89a17;
--C_SEC: #44968e;
--C_TER: #2a5999;
+ --C_TERL: #7ba2d0;
--C_OK: #67b60a;
--C_TRIADIC1: #85ea11;
--C_TRIADIC2: #11ea76;
--C_BG1: #c0ccdf;
--C_BG2: #e3ecf3;
--C_BG3: #e9f3e3;
+ --C_BG4: #DEE6ED;
--C_UNKNOWN: #f84c17;
--C_TEXTINPUT_COLOR: #2f4c6e;
@@ -18,21 +20,52 @@ body{
--MAINBOX_WIDTH: 30em;
}
-input[type="text"] {
- font-family: 'Faustina', serif;
- font-size: 32px;
- border-color: #2a5999;
- border-width: 0 0 0.1em 0;
+h1 {
+ font-size: 40px;
}
-input[type="text"]:focus {
+body {
+ display: block;
+ /*position: fixed;*/
+ top: 0;
+ right: 0;
+ /*bottom: 0;*/
+ left: 0;
+ margin: 0;
+}
+
+h1, h2, h3, h4 {
+ padding: 0.1em 1em;
+}
+
+input[type="text"],
+input[type="password"] {
+ font-family: 'Faustina', serif;
+ font-size: 32px;
+ border-width: 0 0 0.1em 0;
+ border-color: #2a5999;
+
+ background: repeating-linear-gradient(
+ -45deg,
+ var(--C_BG2),
+ var(--C_BG2) 3px,
+ var(--C_BG4) 3px,
+ var(--C_BG4) 6px
+ );
+}
+
+input[type="text"]:focus,
+input[type="password"]:focus{
outline: none;
+ border-color: var(--C_TERL);
}
input#nameinput {
+ display: inline-block;
width: 100%;
color: var(--C_TEXTINPUT_COLOR);
transition: color 0.3s ease;
+ padding: 0 0.5em;
}
input#nameinput[validity="ok"] {
@@ -46,22 +79,47 @@ input#nameinput[validity="bad"] {
}
section#hintbox {
- background-color: var(--C_BG2);
- margin: 0.2em 0.5em;
+ margin: 0.2em 0;
color: var(--C_TER);
font-size: 24px;
padding: 0.5em 0;
}
+section#hintzone {
+ background-color: var(--C_BG2);
+ overflow: hidden;
+ border-bottom: 8px dashed white;
+}
+
+section#hintzone[collapsed="true"] {
+ max-height: 0;
+ transition: max-height 0.3s ease;
+ border-bottom-width: 0;
+}
+
+section#hintzone[collapsed="false"] {
+ max-height: 100em;
+ transition: max-height 0.3s ease;
+ border-bottom-width: 8px;
+}
+
+
span.hit {
display: block;
position: static;
padding: 0.2em 0.5em;
cursor: pointer;
+ text-align: left;
+
+ border-left-width: 0;
+ transition: border-left-width 0.3s ease;
}
span.hit:hover {
background-color: var(--C_BG3);
+ border-left: 8px dotted var(--C_BG2);
+ border-right: 8px dotted var(--C_BG2);
+ transition: border-left-width 0.3s ease;
}
span.highlight {
@@ -72,20 +130,160 @@ span.highlight {
section#mainbox {
display: block;
- position: absolute;
- width: min(var(--MAINBOX_WIDTH), calc(100vw - 1em));
+ /*position: absolute;*/
+ /*width: min(var(--MAINBOX_WIDTH), calc(100vw - 1em));*/
+ width: 100%;
+ /*top: 3em;*/
+ /*left: 50%;*/
+ /*transform: translate(-50%, 0);*/
+ overflow: hidden;
}
+div.btn {
+ /*width: 4em;*/
+ display: inline-block;
+ position: relative;
+ /*top: 0.555em;*/
+ background-color: var(--C_TER);
+ color: white;
+ font-size: 28px;
+ padding: 0 0.2em 0 0.2em;
+ border-radius: 0.2em;
+ /*text-indent: -3px;*/
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+ padding-bottom: 0.2em;
+ margin: 0.1em 0;
+}
+
+div.btn:hover {
+ background-color: var(--C_TERL);
+ transition: background-color 0.3s ease;
+}
+
+div#submitbtn {
+ /*margin-top: 0.2em;*/
+ display: block;
+ width: 100%;
+ text-align: center;
+ border-radius: 0;
+ padding: 0;
+ overflow: hidden;
+ margin-top: 0;
+}
+
+div#submitbtn[collapsed="true"] {
+ height: 0 !important;
+ transition: height 0.3s ease;
+}
+
+div#submitbtn[collapsed="false"] {
+ height: 1.25em;
+ border-bottom: 8px dashed var(--C_BG2);
+ padding-bottom: 0.2em;
+ transition: height 0.3s ease;
+}
+
+input[type="text"]#idinput {
+ align-content: center;
+ width: 100%;
+ margin-bottom: 0.2em;
+ text-align: center;
+}
+
+section#display {
+ display: block;
+ position: relative;
+ /*width: min(var(--MAINBOX_WIDTH), calc(100vw - 1em));*/
+ width: max-content;
+ border-top: 8px dashed white;
+ border-bottom: 8px dashed white;
+ background-color: var(--C_BG2);
+ margin: 3em auto;
+ /*top: 3em;*/
+ padding: 2em 0;
+ overflow-x: hidden;
+ text-align: center;
+}
+
+section#elector_index {
+ background: var(--C_TER);
+ display: inline-block;
+ font-size: 50px;
+ padding: 0.15em 0.4em 0.3em 0.4em;
+ border-left: 8px dashed var(--C_BG2);
+ border-right: 8px dashed var(--C_BG2);
+ color: white;
+}
+
+section#full_records {
+ font-size: 20px;
+ animation: fadeIn 3s forwards;
+ opacity: 0;
+}
+
+@media only screen and (max-width: 600px) {
+ section#display {
+ width: 100vw;
+ }
+ h1, h2, h3, h4 {
+ padding: 0.1em 0.5em;
+ }
+}
+
+/* ------------------------ */
+
*[shown="false"] {
visibility: hidden;
- display: none;
+ display: none !important;
opacity: 0;
- transition: 0.3s ease;
+ transition: opacity 0.5s ease;
width: 0;
height: 0;
+ /*animation: fadeOut 0.3s ease;*/
}
*[shown="true"] {
opacity: 1;
- transition: 0.3s ease;
+ transition: opacity 0.5s ease;
+ /*animation: fadeIn 0.3s ease-out;*/
}
+
+*[collapsed="true"] {
+ max-height: 0;
+ transition: max-height 0.3s ease;
+}
+
+/*@keyframes fadeIn {
+ 0% {
+ display: none;
+ opacity: 0;
+ }
+
+ 1% {
+ display: unset;
+ opacity: 0;
+ }
+
+ 100% {
+ display: unset;
+ opacity: 1;
+ }
+}
+
+@keyframes fadeOut {
+ 0% {
+ display: unset;
+ opacity: 1;
+ }
+
+ 99% {
+ display: unset;
+ opacity: 0;
+ }
+
+ 100% {
+ display: none;
+ opacity: 0;
+ }
+}*/
\ No newline at end of file