Real Initial commit
This commit is contained in:
parent
7eeaba7b7b
commit
4843e664b1
BIN
common/kok-144x144.png
Normal file
BIN
common/kok-144x144.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
47
common/main.css
Normal file
47
common/main.css
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
body{
|
||||||
|
font-family: "Red Hat Display", Myriad, Cantarell, "Noto Sans", "Liberation Sans","Trebuchet MS", Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
|
||||||
|
border-collapse: collapse;
|
||||||
|
line-height: 1.1rem;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
border: 1px solid rgb(192, 192, 192);
|
||||||
|
padding: 0.8rem;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
transition: 0.1s;
|
||||||
|
}
|
||||||
|
tr:nth-child(even){background-color: #f2f2f2;}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
background-color: #c5cae9;
|
||||||
|
}
|
||||||
|
tr:visited {
|
||||||
|
background-color:#c5cae9;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
padding-top: 12px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.hiddendiv {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.nav-link{
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.fade{
|
||||||
|
transition: 0.13s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button4:hover {background-color: #e7e7e7;}
|
248
index.php
Normal file
248
index.php
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" http-equiv="Content-Type" />
|
||||||
|
<meta name="theme-color" content="#1a237e">
|
||||||
|
<title>Liveresultater</title>
|
||||||
|
|
||||||
|
<link rel="icon" type="image/png" href="./common/kok-144x144.png">
|
||||||
|
<link rel="stylesheet" href="common/bootstrap/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="common/main.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar navbar-dark shadow" style="background-color: #303f9f;">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="#">
|
||||||
|
<img src="./common/kok-144x144.png" width="30" height="30" class="d-inline-block align-top" alt="" loading="lazy">
|
||||||
|
Liveresultater
|
||||||
|
</a>
|
||||||
|
<div>
|
||||||
|
<span class="navbar-text mr-md-3" id="lastUpdate">
|
||||||
|
Status
|
||||||
|
</span>
|
||||||
|
<span class="navbar-text" id="lastMessage">
|
||||||
|
Status
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container alert alert-warning hiddendiv" role="alert" id="ConnectionAlert">
|
||||||
|
Du har mistet kontakten med serveren. Last inn sida på nytt får å koble til igjen <button type="button" class="btn btn-warning" onclick="location.reload()">Last inn på nytt</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="container nav nav-pills bd-highlight" id="classes-tabs" role="tablist" style="margin-bottom: 1rem; margin-top: 1rem;">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a class="nav-link active" id="alle-tab" data-toggle="tab" href="#alle" role="tab" aria-controls="alle" aria-selected="true">Alle klasser</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content" id="classes-tab-content">
|
||||||
|
<div class="tab-pane fade show active" id="alle" role="tabpanel" aria-labelledby="alle">
|
||||||
|
<div class="container" id="alle-cont"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="liveresults" class="container"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var tabsCreated = false;
|
||||||
|
|
||||||
|
function createTabs(tabArray) {
|
||||||
|
for (let i = 0; i < tabArray.length; i++) {
|
||||||
|
let startStrTab = '<li class="nav-item" role="presentation"><a class="nav-link" role="tab" data-toggle="tab"'
|
||||||
|
|
||||||
|
let StrTab = startStrTab + 'id="' + tabArray[i] + '-tab" href="#' + tabArray[i] + '" aria-controls="' + tabArray[i] + '" aria-selected="false">' + tabArray[i].replace(/_/g, " ") + '</a></li>';
|
||||||
|
let StrCont = '<div class="tab-pane fade show" id="' + tabArray[i] + '" role="tabpanel" aria-labelledby="' + tabArray[i] + '-tab"></div>'
|
||||||
|
document.getElementById("classes-tabs").innerHTML += StrTab;
|
||||||
|
document.getElementById("classes-tab-content").innerHTML += StrCont;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function diff_minutes(dt2, dt1) {
|
||||||
|
|
||||||
|
let diff = (dt2.getTime() - dt1.getTime()) / 1000;
|
||||||
|
//diff /= 60;
|
||||||
|
let minutes = Math.floor(diff / 60);
|
||||||
|
let seconds = diff - minutes * 60;
|
||||||
|
let hours = Math.floor(diff / 3600);
|
||||||
|
|
||||||
|
return minutes + ":" + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function diff_timestamp(dt2, dt1) {
|
||||||
|
let diff = (dt2.getTime() - dt1.getTime()) / 1000;
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortTable(tableToCheck) {
|
||||||
|
var table, rows, switching, i, x, y, shouldSwitch;
|
||||||
|
table = document.getElementById(tableToCheck);
|
||||||
|
switching = true;
|
||||||
|
/* Make a loop that will continue until
|
||||||
|
no switching has been done: */
|
||||||
|
while (switching) {
|
||||||
|
// Start by saying: no switching is done:
|
||||||
|
switching = false;
|
||||||
|
rows = table.rows;
|
||||||
|
/* Loop through all table rows (except the
|
||||||
|
first, which contains table headers): */
|
||||||
|
for (i = 1; i < (rows.length - 1); i++) {
|
||||||
|
// Start by saying there should be no switching:
|
||||||
|
shouldSwitch = false;
|
||||||
|
/* Get the two elements you want to compare,
|
||||||
|
one from current row and one from the next: */
|
||||||
|
x = rows[i].getElementsByTagName("td")[2];
|
||||||
|
y = rows[i + 1].getElementsByTagName("td")[2];
|
||||||
|
// Check if the two rows should switch place:
|
||||||
|
console.log(parseInt(x.className, 10));
|
||||||
|
console.log(parseInt(y.className, 10));
|
||||||
|
if (parseInt(x.className, 10) > parseInt(y.className, 10)) {
|
||||||
|
// If so, mark as a switch and break the loop:
|
||||||
|
shouldSwitch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shouldSwitch) {
|
||||||
|
/* If a switch has been marked, make the switch
|
||||||
|
and mark that a switch has been done: */
|
||||||
|
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
|
||||||
|
switching = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < (rows.length); i++) {
|
||||||
|
rows[i].getElementsByTagName("td")[0].innerHTML = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function loadresults() {
|
||||||
|
var xmlhttp = new XMLHttpRequest();
|
||||||
|
xmlhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
let xmlObj = JSON.parse(this.responseText);
|
||||||
|
|
||||||
|
var classesArray = [];
|
||||||
|
for (let i = 0; i < xmlObj.ClassResult.length; i++) {
|
||||||
|
classesArray[i] = xmlObj.ClassResult[i].Class.Name.replace(/ /g, "_");;
|
||||||
|
}
|
||||||
|
console.log(classesArray);
|
||||||
|
if (tabsCreated == false) {
|
||||||
|
createTabs(classesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
//create tables
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < xmlObj.ClassResult.length; i++) {
|
||||||
|
let resultTable = '<table class="container" id="'+classesArray[i].replace(/ /g, "_")+'-table">'
|
||||||
|
for (let k = 0; k < xmlObj.ClassResult[i].PersonResult.length; k++) {
|
||||||
|
resultTable += '<tr><td id="Ranking"></td>'
|
||||||
|
resultTable += "<td>" + xmlObj.ClassResult[i].PersonResult[k].Person.Name.Given + " " + xmlObj.ClassResult[i].PersonResult[k].Person.Name.Family + "</td>"
|
||||||
|
|
||||||
|
let d1 = new Date(xmlObj.ClassResult[i].PersonResult[k].Result.FinishTime);
|
||||||
|
let d2 = new Date(xmlObj.ClassResult[i].PersonResult[k].Result.StartTime);
|
||||||
|
let timeUsed = diff_minutes(d1, d2);
|
||||||
|
|
||||||
|
resultTable += '<td class="'+diff_timestamp(d1, d2)+'">' + timeUsed + '</td>'
|
||||||
|
resultTable += "</tr>"
|
||||||
|
|
||||||
|
}
|
||||||
|
document.getElementById(classesArray[i].replace(/ /g, "_")).innerHTML = resultTable;
|
||||||
|
resultTable += "</table>"
|
||||||
|
console.log(classesArray[i].replace(/ /g, "_")+'-table');
|
||||||
|
sortTable(classesArray[i].replace(/ /g, "_")+'-table');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(xmlObj)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xmlhttp.open("GET", "xmlToJson.php", true);
|
||||||
|
xmlhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadresults()
|
||||||
|
|
||||||
|
function mkTimeStr(timestmp) {
|
||||||
|
var date = new Date(timestmp * 1000);
|
||||||
|
// Hours part from the timestamp
|
||||||
|
var hours = date.getHours();
|
||||||
|
// Minutes part from the timestamp
|
||||||
|
var minutes = "0" + date.getMinutes();
|
||||||
|
// Seconds part from the timestamp
|
||||||
|
var seconds = "0" + date.getSeconds();
|
||||||
|
|
||||||
|
// Will display time in 10:30:23 format
|
||||||
|
var formattedTime = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
|
||||||
|
|
||||||
|
return formattedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var lastUpdate;
|
||||||
|
|
||||||
|
if (typeof(EventSource) !== "undefined") {
|
||||||
|
var source = new EventSource("updater.php");
|
||||||
|
source.onmessage = function(event) {
|
||||||
|
//console.log(event);
|
||||||
|
statusArray = event.data.split(",");
|
||||||
|
lastMessage = parseInt(statusArray[3], 10);
|
||||||
|
console.log(statusArray);
|
||||||
|
|
||||||
|
//document.getElementById("result").innerHTML += event.data + "<br>";
|
||||||
|
|
||||||
|
document.getElementById("lastUpdate").innerHTML = "Siste oppdatering: " + mkTimeStr(statusArray[1]);
|
||||||
|
document.getElementById("lastMessage").innerHTML = "Siste melding fra server: " + mkTimeStr(statusArray[2]);
|
||||||
|
//document.getElementById("liveresult").innerHTML = event.data + "<br>";
|
||||||
|
|
||||||
|
updateInt = parseInt(statusArray[0], 10);
|
||||||
|
console.log(updateInt);
|
||||||
|
if (window.lastUpdate + 5 < parseInt(statusArray[1], 10)) {
|
||||||
|
updateInt = 1;
|
||||||
|
}
|
||||||
|
if (lastUpdate == undefined) {
|
||||||
|
window.lastUpdate == parseInt(statusArray[1], 10)
|
||||||
|
}
|
||||||
|
console.log(statusArray);
|
||||||
|
|
||||||
|
if (updateInt == 1) {
|
||||||
|
loadresults()
|
||||||
|
console.log("Update!!!!! :=)");
|
||||||
|
window.lastUpdate = parseInt(statusArray[1], 10);
|
||||||
|
|
||||||
|
var jdata = JSON.parse(statusArray[3]);
|
||||||
|
console.log(jdata);
|
||||||
|
} else {
|
||||||
|
console.log("No update");
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
document.getElementById("serverStatus").innerHTML = "Sorry, your browser does not support server-sent events...";
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkConnection = async function() {
|
||||||
|
cTime = Math.round(Date.now() / 1000);
|
||||||
|
|
||||||
|
if (cTime > lastMessage + 30) {
|
||||||
|
//mistet tilkobling
|
||||||
|
var element = document.getElementById("ConnectionAlert");
|
||||||
|
element.classList.remove("hiddendiv");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//fortsatt tilkoblet
|
||||||
|
var element = document.getElementById("ConnectionAlert");
|
||||||
|
element.classList.add("hiddendiv");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var interval = setInterval(checkConnection, 10000);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="common/bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
59
updater.php
Normal file
59
updater.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
set_time_limit( 0 );
|
||||||
|
ini_set('auto_detect_line_endings', 1);
|
||||||
|
ini_set('mysql.connect_timeout','7200');
|
||||||
|
ini_set('max_execution_time', '0');
|
||||||
|
|
||||||
|
date_default_timezone_set( 'Europe/Oslo' );
|
||||||
|
ob_end_clean();
|
||||||
|
gc_enable();
|
||||||
|
|
||||||
|
header('Content-Type: text/event-stream');
|
||||||
|
header('Cache-Control: no-cache');
|
||||||
|
header('Access-Control-Allow-Credentials: true');
|
||||||
|
header('Access-Control-Allow-Methods: GET');
|
||||||
|
header('Access-Control-Expose-Headers: X-Events');
|
||||||
|
|
||||||
|
include 'lastSavedChange.php';
|
||||||
|
|
||||||
|
$resultFile = "ttime-res/Resultater.xml";
|
||||||
|
//load variable from last check
|
||||||
|
$lastChange = filemtime($resultFile);
|
||||||
|
$time = date('r');
|
||||||
|
|
||||||
|
if ($lastSavedChange == NULL){
|
||||||
|
$lastSavedChange = $lastChange;
|
||||||
|
}
|
||||||
|
//check if file has been updated
|
||||||
|
if ($lastSavedChange<$lastChange){
|
||||||
|
//update deteceted
|
||||||
|
$ischanged = "yes :)";
|
||||||
|
$var_str = var_export($lastChange, true);
|
||||||
|
$var = "<?php\n\n\$lastSavedChange = $var_str;\n\n?>";
|
||||||
|
file_put_contents('lastSavedChange.php', $var, LOCK_EX);
|
||||||
|
$objXmlDocument = simplexml_load_file("ttime-res/Resultater.xml");
|
||||||
|
|
||||||
|
//xml to json
|
||||||
|
if ($objXmlDocument === FALSE) {
|
||||||
|
foreach(libxml_get_errors() as $error) {
|
||||||
|
//error :(
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$objJsonDocument = json_encode($objXmlDocument);
|
||||||
|
$arrOutput = json_decode($objJsonDocument, TRUE);
|
||||||
|
|
||||||
|
//csv format: change boolian , last time the xml was changed, current server time, json from xml
|
||||||
|
$response = "1,". $lastChange. "," . time() . "," . $objJsonDocument;
|
||||||
|
echo "data: $response\n\n";
|
||||||
|
}
|
||||||
|
elseif ($lastSavedChange==NULL){
|
||||||
|
//file does not exist
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//no update deteceted
|
||||||
|
$response = "0,". $lastChange. "," . time() . "," ;
|
||||||
|
echo "data: $response\n\n";
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
?>
|
15
xmlToJson.php
Normal file
15
xmlToJson.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
libxml_use_internal_errors(TRUE);
|
||||||
|
$objXmlDocument = simplexml_load_file("ttime-res/Resultater.xml");
|
||||||
|
|
||||||
|
if ($objXmlDocument === FALSE) {
|
||||||
|
foreach(libxml_get_errors() as $error) {
|
||||||
|
//error
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$objJsonDocument = json_encode($objXmlDocument);
|
||||||
|
$arrOutput = json_decode($objJsonDocument, TRUE);
|
||||||
|
|
||||||
|
echo $objJsonDocument;
|
||||||
|
?>
|
Loading…
Reference in New Issue
Block a user