Első release
This commit is contained in:
parent
fc5e4eb54e
commit
cbcdb7115a
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -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
|
||||
8
.idea/mkkkvv.iml
generated
Normal file
8
.idea/mkkkvv.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/mkkkvv.iml" filepath="$PROJECT_DIR$/.idea/mkkkvv.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/php.xml
generated
Normal file
6
.idea/php.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
58
control_panel.php
Normal file
58
control_panel.php
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="hu">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>MKK Közivezető-választás vezérlőpult</title>
|
||||
<script src="js/req.js"></script>
|
||||
<script src="js/o.js"></script>
|
||||
<script src="js/mkkkvv_cp.js"></script>
|
||||
<link rel="stylesheet" href="mkkkvv.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<section id="display">
|
||||
<h1>Közivezető-választás vezérlőpult</h1>
|
||||
<section id="loginbox" shown="true">
|
||||
<section>
|
||||
<input type="text" placeholder="Vezérlőpult-azonosító" id="cpidinput"
|
||||
style="margin-bottom: 0.4em; text-align: center; width: 100%"><br>
|
||||
<div class="btn" onclick="cp_login()">Belépés</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="control_panel" shown="false">
|
||||
<section id="short_info">
|
||||
<img alt="Betöltés..." src="media/spinner.svg" style="width: 40%;">
|
||||
</section>
|
||||
<section>
|
||||
<h2>Szavazás-vezérlés</h2>
|
||||
<div class="btn" id="openelectionbtn" onclick="cp_modify_state('open_election');">Szavazás megnyitása</div>
|
||||
<div class="btn" id="closeelectionbtn" onclick="cp_modify_state('close_election');">Szavazás lezárása</div>
|
||||
<section id="submitbox">
|
||||
<div class="btn" id="enablesubmitbtn" onclick="cp_modify_state('enable_submitting')">Voksolás
|
||||
engedélyezése
|
||||
</div>
|
||||
<div class="btn" id="disablesubmitbtn" onclick="cp_modify_state('disable_submitting')">Voksolás
|
||||
tiltása
|
||||
</div>
|
||||
</section>
|
||||
<br>
|
||||
<section id="publishbox">
|
||||
<input type="checkbox" onchange="cp_toggle_publish_results(this.checked);" id="publishchkbox">Tudom, a
|
||||
nyilvánosságra hozott infók nem igazán vonhatók már vissza...<br>
|
||||
<div class="btn" id="publishbtn" shown="false"
|
||||
onclick="if (o('publishchkbox').checked) { cp_modify_state('publish_results'); o('publishchkbox').checked = false; hide('publishbtn'); }">
|
||||
Összesítés és nyilvánosságra hozás
|
||||
</div>
|
||||
</section>
|
||||
<div class="btn" id="undopublishbtn" onclick="cp_modify_state('unpublish_results');">Nyilvánosságra hozás
|
||||
visszavonása
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div class="btn" onclick="cp_internal_totaling()">Zárt összesítés és megjelenítés</div>
|
||||
</section>
|
||||
</section>
|
||||
<script>
|
||||
o("publishchkbox").checked = false;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
39
index.php
39
index.php
@ -1,11 +1,19 @@
|
||||
<?php
|
||||
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
|
||||
|
||||
$mobile = false;
|
||||
if (strstr($user_agent, "mobile")) {
|
||||
$mobile = true;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="hu">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0'>
|
||||
<title>MKK Közivezető-választás</title>
|
||||
<script src="js/req.js"></script>
|
||||
<script src="js/o.js"></script>
|
||||
@ -13,13 +21,36 @@
|
||||
<link rel="stylesheet" href="mkkkvv.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<section id="mainbox">
|
||||
<input oninput="search_in_names(this.value)"
|
||||
<section id="display">
|
||||
<h1>Közivezető-választás</h1>
|
||||
<section id="loginbox" shown="true">
|
||||
<section>
|
||||
<input type="text" placeholder="Add meg az azonosítód!" id="idinput" <?php if (isset($_GET["id"])) echo "value=\"${_GET['id']}\""; ?> ><br>
|
||||
<div class="btn" id="loginbtn" onclick="login()">Belépés</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="infobox" shown="false">
|
||||
<h3 id="infoheader"></h3>
|
||||
</section>
|
||||
<section id="mainbox" shown="false">
|
||||
<input oninput="search_in_names();"
|
||||
type="text" placeholder="Ki legyen a Közivezető? :)" id="nameinput">
|
||||
<section id="hintzone" shown="false">
|
||||
<section id="hintbox">
|
||||
<div id="submitbtn" class="btn" collapsed="true" onclick="submit_name()">Mehet!</div>
|
||||
<section id="hintzone" collapsed="true">
|
||||
<section id="hintbox"></section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="thankbox" shown="false">
|
||||
<h2>Köszönjük, te vagy a...</h2>
|
||||
<section id="elector_index">42.</section>
|
||||
<h2>...szavazó!</h2>
|
||||
<h3>Feltétlen nézz vissza később az eredményekért!</h3>
|
||||
</section>
|
||||
<section id="resultbox" shown="false">
|
||||
<img src="media/spinner.svg" alt="Betöltés..." style="width: 40%">
|
||||
</section>
|
||||
<script>
|
||||
let MOBILE = <?=$mobile ? "true" : "false"?>;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
693
interface.php
693
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 "<path id='$id' d='$d' stroke='$color' fill='none' stroke-width='$stroke_width' class='$class' />\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 "<rect x='$rect_x' y='$rect_y' width='$mark_size' height='$mark_size' fill='$color' rx='4' />
|
||||
return "<circle cx='$rect_x' cy='$rect_y' r='$circ_radius' fill='$color' cursor='pointer'/>
|
||||
<text class='legend' x='$text_x' y='$text_y' text-anchor='$text_anchor'>$text</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 .= "<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Faustina');
|
||||
.legend { font-family: 'Faustina', serif; font-size: ${legend_font_size}px; dominant-baseline: middle; cursor: pointer; }
|
||||
.sector { cursor: pointer; }
|
||||
.sector:hover { stroke-width: ${hlsw}px }
|
||||
.sectorlabel { font-family: 'Faustina', serif; fill: white; text-anchor: middle; dominant-baseline: middle; cursor: pointer; }
|
||||
g.datagroup { animation: fadeIn ${animdur}s forwards; opacity: 0; }
|
||||
g.datagroup:hover .sector { stroke-width: ${hlsw}px; }
|
||||
@keyframes fadeIn {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
</style>";
|
||||
|
||||
$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 .= "<g class='datagroup' style='animation-delay: ${anim_delay}s' id='datagroup${idx}'>";
|
||||
$sector_id = "sector$idx";
|
||||
$svg .= $svg_path($svg_curve($percent), $color, "$sector_id"); // körcikk
|
||||
$svg .= "<text><textPath class='sectorlabel' href='#$sector_id' startOffset='50%'>" // szöveg rajta
|
||||
. number_format((float)$percent, 1, ',', '') .
|
||||
"%</textPath></text>\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 .= "</g>";
|
||||
|
||||
$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 = "<svg viewBox='$viewBox' xmlns='http://www.w3.org/2000/svg' $style>" . $svg;
|
||||
|
||||
|
||||
$svg .= "</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 "login":
|
||||
{
|
||||
$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 "cp_login":
|
||||
{
|
||||
$cp_id = $req_data["cp_id"] ?? "";
|
||||
$res = cp_verify_id($cp_id);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$processed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// ha feldolgozta, akkor ugrás a végére (inkább a goto, mint 46 zárójel... :D)
|
||||
if ($processed) {
|
||||
goto exit_point; // --->
|
||||
}
|
||||
|
||||
// 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":
|
||||
{
|
||||
$needle = json_decode($_POST["needle"]);
|
||||
$group = json_decode($_POST["group"]);
|
||||
if (!$state["open_for_submit"] && !$admin_login) {
|
||||
break;
|
||||
}
|
||||
|
||||
$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 "none":
|
||||
case "submit":
|
||||
{
|
||||
if (!$state["open_for_submit"] && !$admin_login) {
|
||||
break;
|
||||
}
|
||||
|
||||
echo json_encode($res);
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
//$p = read_electable_people("data/electable_people_test.md");
|
||||
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;
|
||||
227
js/mkkkvv.js
227
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 = `<h2>Eredmények</h2>`
|
||||
resbox.innerHTML = headline + `<img alt="Betöltés..." src="media/spinner.svg" style="width: 40%;">`;
|
||||
|
||||
// grafikon betöltése
|
||||
let load_pie_req = new XMLHttpRequest();
|
||||
load_pie_req.addEventListener("load", () => {
|
||||
let str = headline + load_pie_req.response;
|
||||
str += `<section id="full_records"><h3>Teljes összesítés:</h3>`
|
||||
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 += `<b>${i+1}.</b> ${rec["name"]} (${percent}%, ${rec["count"]} szavazat)<br>`;
|
||||
}
|
||||
str += "<br>";
|
||||
str += `...összesen <b>${total_count}</b> szavazat alapján! Gratulálunk! :)</section>`
|
||||
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 = `<h3>Még nem elérhetők az eredmények, de mi is kíváncsian várjuk! :)</h3>`
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// #003f5c
|
||||
// #444e86
|
||||
// #955196
|
||||
// #dd5182
|
||||
// #ff6e54
|
||||
// #ffa600
|
||||
|
||||
// #003f5c
|
||||
// #424d83
|
||||
// #8e5092
|
||||
// #d24f81
|
||||
// #fa6756
|
||||
// #f89a17
|
||||
114
js/mkkkvv_cp.js
Normal file
114
js/mkkkvv_cp.js
Normal file
@ -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 = `<h2>Összefoglaló információk</h2>
|
||||
<h4>Szavazatok: ${report["total_votes"]}/${report["total_electors"]}</span></h4>`;
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
12
js/o.js
12
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");
|
||||
}
|
||||
78
media/arrow.svg
Normal file
78
media/arrow.svg
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1.5541884mm"
|
||||
height="0.86403mm"
|
||||
viewBox="0 0 1.5541884 0.86403"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="arrow.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="64"
|
||||
inkscape:cx="3.4065978"
|
||||
inkscape:cy="2.5660352"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="text817"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1117"
|
||||
inkscape:window-x="1200"
|
||||
inkscape:window-y="360"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid822"
|
||||
originx="-84.335001"
|
||||
originy="-162.026" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="1. réteg"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-84.335,-134.10997)">
|
||||
<g
|
||||
aria-label="⤐"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.11666656px;line-height:268.45001221;font-family:Monaco;-inkscape-font-specification:Monaco;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
id="text817">
|
||||
<path
|
||||
d="m 85.11714,134.45827 v 0.16743 h -0.15503 v -0.16743 z m 0.450618,0.16743 -0.367936,0.3483 h -0.01137 l 0.199471,-0.3483 h -0.136426 v -0.16743 h 0.136426 l -0.199471,-0.3483 h 0.01137 l 0.367936,0.3483 h 0.07855 l -0.199471,-0.3483 h 0.01137 l 0.430981,0.42685 v 0.0103 l -0.430981,0.42685 h -0.01137 l 0.199471,-0.3483 z m -0.790649,0 -0.295294,0.29219 c -0.03035,0.0313 -0.04869,0.0543 -0.106024,-9e-5 -0.0489,-0.0554 -0.04419,-0.0727 -0.01331,-0.10827 l 0.257496,-0.26222 v -0.0103 l -0.263402,-0.25631 c -0.03489,-0.0458 -0.0248,-0.0699 0.0112,-0.11218 0.04421,-0.0396 0.06897,-0.045 0.111053,-0.01 l 0.298247,0.29958 h 0.05064 v 0.16743 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto Sans Coptic';-inkscape-font-specification:'Noto Sans Coptic';stroke-width:0.26458332"
|
||||
id="path819"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
7
media/spinner.svg
Normal file
7
media/spinner.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M -5 0
|
||||
A 5 5 0 1 1 0 5" stroke-width="2" stroke="#7ba2d0" fill="none"></path>
|
||||
<path d="M -5 0
|
||||
A 5 5 0 0 0 0 5" stroke-width="2" stroke="#2a5999" fill="none"></path>
|
||||
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="360 0 0" to="0 0 0" dur="5s" additive="sum" repeatCount="indefinite" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 420 B |
224
mkkkvv.css
224
mkkkvv.css
@ -4,12 +4,14 @@ 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;
|
||||
}
|
||||
}*/
|
||||
Loading…
x
Reference in New Issue
Block a user