summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2025-07-25 16:44:53 +0200
committerSimon Rettberg2025-07-25 16:44:53 +0200
commitbdd2d06844d1a0eb2a68235b582845c1de00229c (patch)
tree3c652a1523bed4cc78795bf3b468b9b28a8dab72
parent[roomplanner] Add type annotations, change falsable -> nullable (diff)
downloadslx-admin-bdd2d06844d1a0eb2a68235b582845c1de00229c.tar.gz
slx-admin-bdd2d06844d1a0eb2a68235b582845c1de00229c.tar.xz
slx-admin-bdd2d06844d1a0eb2a68235b582845c1de00229c.zip
[locationinfo] Make sure older browsers work by using proper JavaScript
Not funny made-up words like async and let and random keyboard smashing of the "." key.
-rw-r--r--modules-available/locationinfo/frontend/frontendscript.js91
-rw-r--r--modules-available/locationinfo/frontend/webapk.js45
-rw-r--r--modules-available/locationinfo/page.inc.php3
-rwxr-xr-xmodules-available/locationinfo/templates/frontend-default.html22
-rw-r--r--modules-available/locationinfo/templates/frontend-summary.html6
-rw-r--r--modules-available/locationinfo/templates/frontend-upcoming.html8
6 files changed, 98 insertions, 77 deletions
diff --git a/modules-available/locationinfo/frontend/frontendscript.js b/modules-available/locationinfo/frontend/frontendscript.js
index 0d336d14..38fc0f79 100644
--- a/modules-available/locationinfo/frontend/frontendscript.js
+++ b/modules-available/locationinfo/frontend/frontendscript.js
@@ -3,12 +3,13 @@ var slxAllTimeouts = {};
(function() {
const originalSetTimeout = window.setTimeout;
- window.setTimeout = function(callback, delay, ...args) {
+ window.setTimeout = function(callback, delay) {
+ const args = Array.prototype.slice.call(arguments, 2);
const wrapCb = function() {
delete slxAllTimeouts[id];
- callback(...args);
+ callback.apply(null, args);
}
- const id = originalSetTimeout(wrapCb, delay, ...args);
+ const id = originalSetTimeout(wrapCb, delay);
slxAllTimeouts[id] = true;
return id;
};
@@ -18,8 +19,11 @@ var slxAllTimeouts = {};
originalClearTimeout(id);
};
const originalSetInterval = window.setInterval;
- window.setInterval = function(callback, delay, ...args) {
- const id = originalSetInterval(callback, delay, ...args);
+ window.setInterval = function(callback, delay) {
+ const args = Array.prototype.slice.call(arguments, 2);
+ const id = originalSetInterval(function() {
+ callback.apply(null, args);
+ }, delay);
slxAllIntervals[id] = true;
return id;
};
@@ -156,52 +160,6 @@ function GetTimeDiferenceAsString(a, b, globalConfig) {
return hours + ":" + minutes + ":" + seconds;
}
-const getWebApk = async function (fileName, manifestUrl = document.querySelector("link[rel=manifest]").href) {
- Uint8Array.prototype.toBase64 ??= function () {
- return btoa(Array.from(this, v => String.fromCharCode(v)).join(""));
- }
-
- const manifest = await (await fetch(manifestUrl)).json();
- if (!manifest.start_url) {
- alert('Manifest start_url missing');
- return;
- }
- if (!manifest.icons) {
- alert('Manifest icons missing');
- return;
- }
- const startUrl = new URL(manifest.start_url, manifestUrl);
- const imageData = new Uint8Array(await (await fetch(new URL(manifest.icons.find(v => v.type === "image/png").src, manifestUrl))).arrayBuffer()).toBase64();
-
- const {downloadUrl} = await (
- await fetch("https://webapk.googleapis.com/v1/webApks/?key=AIzaSyAoI6v-F31-3t9NunLYEiKcPIqgTJIUZBw", {
- method: "POST",
- body: JSON.stringify({
- appKey: startUrl, manifestUrl, requesterApplicationPackage: "com.android.chrome",
- manifest: {
- name: manifest.name,
- startUrl,
- id: startUrl,
- scopes: [new URL(".", startUrl)],
- icons: [{imageData}],
- displayMode: manifest.display
- }
- }),
- headers: {
- "content-type": "application/json",
- },
- })
- ).json();
-
- if (typeof downloadUrl !== 'string') {
- alert('Error generating APK');
- return;
- }
-
- location = downloadUrl;
- return;
-};
-
/**
* Checks whether the panel has been edited and reloads
* the entire page if so.
@@ -329,17 +287,26 @@ function sanitizeConfigParam(config, property, paramType, defaultValue, min, max
function cleanDate(d) {
if (typeof d === 'string') {
// numeric -> handle as such
- if (!isNaN(Number(d))) {
- return cleanDate(parseInt(d, 10));
+ if (!isNaN(Number(d)) && Number(d) > 0) {
+ return cleanDate(Number(d));
}
-
- // this is a human-readable date, must be ISO8601
- var utc = true;
- if (d[d.length - 1] !== 'Z') {
- // Work around old WebKit bug where an ISO time without any TZ information gets interpreted
+ // this is a human-readable date, must be ISO8601 according to backend
+ if (oldWebkit) {
+ // Very old webkit, doesn't understand ISO8601
+ var o = new Date(d.replace(/-/g, '/')
+ .replace(/(\d)T(\d|$)/, '$1 $2')
+ .replace(/Z$/, ''));
+ if (d.length > 0 && d[d.length - 1] === 'Z') {
+ // Was UTC originally, re-apply offset
+ o.setTime(o.getTime() - (o.getTimezoneOffset() * 60 * 1000));
+ }
+ return o;
+ }
+ const utc = d.length === 0 || d[d.length - 1] === 'Z';
+ if (!utc) {
+ // Work around not-so-old WebKit bug where an ISO time without any TZ information gets interpreted
// as UTC instead of local time, so force interpretation as UTC and then apply timezone manually
d += 'Z';
- utc = false;
}
var o = new Date(d);
if (!utc) {
@@ -356,6 +323,12 @@ function cleanDate(d) {
return d;
}
+const oldWebkit = (function() {
+ var match = navigator.userAgent.match(/AppleWebKit\/([\d.]+)/);
+ var webkitVersion = match ? parseInt(match[1], 10) : null;
+ return (webkitVersion && webkitVersion < 540);
+})();
+
/**
* Function for translation
* @param toTranslate key which we want to translate
diff --git a/modules-available/locationinfo/frontend/webapk.js b/modules-available/locationinfo/frontend/webapk.js
new file mode 100644
index 00000000..73e12bf0
--- /dev/null
+++ b/modules-available/locationinfo/frontend/webapk.js
@@ -0,0 +1,45 @@
+const getWebApk = async function (fileName, manifestUrl = document.querySelector("link[rel=manifest]").href) {
+ Uint8Array.prototype.toBase64 ??= function () {
+ return btoa(Array.from(this, v => String.fromCharCode(v)).join(""));
+ }
+
+ const manifest = await (await fetch(manifestUrl)).json();
+ if (!manifest.start_url) {
+ alert('Manifest start_url missing');
+ return;
+ }
+ if (!manifest.icons) {
+ alert('Manifest icons missing');
+ return;
+ }
+ const startUrl = new URL(manifest.start_url, manifestUrl);
+ const imageData = new Uint8Array(await (await fetch(new URL(manifest.icons.find(v => v.type === "image/png").src, manifestUrl))).arrayBuffer()).toBase64();
+
+ const {downloadUrl} = await (
+ await fetch("https://webapk.googleapis.com/v1/webApks/?key=AIzaSyAoI6v-F31-3t9NunLYEiKcPIqgTJIUZBw", {
+ method: "POST",
+ body: JSON.stringify({
+ appKey: startUrl, manifestUrl, requesterApplicationPackage: "com.android.chrome",
+ manifest: {
+ name: manifest.name,
+ startUrl,
+ id: startUrl,
+ scopes: [new URL(".", startUrl)],
+ icons: [{imageData}],
+ displayMode: manifest.display
+ }
+ }),
+ headers: {
+ "content-type": "application/json",
+ },
+ })
+ ).json();
+
+ if (typeof downloadUrl !== 'string') {
+ alert('Error generating APK');
+ return;
+ }
+
+ location = downloadUrl;
+ return;
+}; \ No newline at end of file
diff --git a/modules-available/locationinfo/page.inc.php b/modules-available/locationinfo/page.inc.php
index a6d56e5a..72c2c167 100644
--- a/modules-available/locationinfo/page.inc.php
+++ b/modules-available/locationinfo/page.inc.php
@@ -1010,7 +1010,8 @@ class Page_LocationInfo extends Page
}
}
- $config['config'] = json_encode($config); // Must be last, obviously
+ $config['config'] = json_encode($config); // Must come after all config options needed in JSON are set
+ $config['jsbump'] = 6; // Bump this every time you touch a JS file do ensure it gets reloaded
die(Render::parse($templateFile, $config, null, $lang));
}
diff --git a/modules-available/locationinfo/templates/frontend-default.html b/modules-available/locationinfo/templates/frontend-default.html
index 5cd044d1..2e446d90 100755
--- a/modules-available/locationinfo/templates/frontend-default.html
+++ b/modules-available/locationinfo/templates/frontend-default.html
@@ -363,10 +363,11 @@ optional:
</style>
- <script type='text/javascript' src='script/jquery.js'></script>
- <script type='text/javascript' src='modules/locationinfo/frontend/frontendscript.js'></script>
- <script type='text/javascript' src='modules/js_jqueryui/clientscript.js'></script>
- <script type='text/javascript' src="modules/js_weekcalendar/clientscript.js"></script>
+ <script type='text/javascript' src='script/jquery.js?_={{jsbump}}'></script>
+ <script type='text/javascript' src='modules/locationinfo/frontend/frontendscript.js?_={{jsbump}}'></script>
+ <script type='text/javascript' src='modules/js_jqueryui/clientscript.js?_={{jsbump}}'></script>
+ <script type='text/javascript' src="modules/js_weekcalendar/clientscript.js?_={{jsbump}}"></script>
+ <script type='text/javascript' src='modules/locationinfo/frontend/webapk.js?_={{jsbump}}'></script>
</head>
<body>
@@ -446,7 +447,7 @@ optional:
console.log(time);
}
if (time === false || isNaN(time.getTime()) || time.getFullYear() < 2010) {
- time = new Date(globalConfig.time);
+ time = cleanDate(globalConfig.time);
}
if (isNaN(time.getTime()) || time.getFullYear() < 2010) {
time = new Date();
@@ -502,8 +503,8 @@ optional:
height = "50%";
}
for (var t = 0; t < roomIds.length; t++) {
- let rid = roomIds[t];
- let room = rooms[rid];
+ var rid = roomIds[t];
+ var room = rooms[rid];
if (roomIds.length === 3) {
top = 0;
left = (t * 33) + '%';
@@ -523,7 +524,7 @@ optional:
room.$.seatsCounter = $('<span>').addClass('seats-counter');
room.$.seatsBackground = $('<div>').addClass('col col-square').append(room.$.seatsCounter);
- let ctr = 0;
+ var ctr = 0;
room.$.seatsBackground.click(function() {
if (ctr++ == 7) {
$(this).text('…');
@@ -919,10 +920,11 @@ optional:
console.log("Notice: Calendar already empty from server");
}
var now = MyDate().getTime();
+
json = json.filter(function (el) {
if (!el.title || !el.start || !el.end) return false;
- var s = new Date(el.start).getTime();
- var e = new Date(el.end).getTime();
+ var s = cleanDate(el.start).getTime();
+ var e = cleanDate(el.end).getTime();
return !(isNaN(s) || isNaN(e) || Math.abs(s - now) > SEVEN_DAYS || Math.abs(e - now) > SEVEN_DAYS);
});
if (json.length === 0) {
diff --git a/modules-available/locationinfo/templates/frontend-summary.html b/modules-available/locationinfo/templates/frontend-summary.html
index 81545d22..74521202 100644
--- a/modules-available/locationinfo/templates/frontend-summary.html
+++ b/modules-available/locationinfo/templates/frontend-summary.html
@@ -2,8 +2,8 @@
<html lang="{{language}}">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8">
- <script type='text/javascript' src='script/jquery.js'></script>
- <script type='text/javascript' src='modules/locationinfo/frontend/frontendscript.js'></script>
+ <script type='text/javascript' src='script/jquery.js?_={{jsbump}}'></script>
+ <script type='text/javascript' src='modules/locationinfo/frontend/frontendscript.js?_={{jsbump}}'></script>
<link rel="manifest" type="application/json" href="api/get=manifest&amp;uuid={{uuid}}">
@@ -140,7 +140,7 @@
console.log(time);
}
if (time === false || isNaN(time.getTime()) || time.getFullYear() < 2010) {
- time = new Date(config.time);
+ time = cleanDate(config.time);
}
if (!time || isNaN(time.getTime()) || time.getFullYear() < 2010) {
time = new Date();
diff --git a/modules-available/locationinfo/templates/frontend-upcoming.html b/modules-available/locationinfo/templates/frontend-upcoming.html
index b1878336..a7a728b7 100644
--- a/modules-available/locationinfo/templates/frontend-upcoming.html
+++ b/modules-available/locationinfo/templates/frontend-upcoming.html
@@ -200,8 +200,8 @@ optional:
}
</style>
- <script type='text/javascript' src='script/jquery.js'></script>
- <script type='text/javascript' src='modules/locationinfo/frontend/frontendscript.js'></script>
+ <script type='text/javascript' src='script/jquery.js?_={{jsbump}}'></script>
+ <script type='text/javascript' src='modules/locationinfo/frontend/frontendscript.js?_={{jsbump}}'></script>
</head>
<body>
@@ -331,8 +331,8 @@ optional:
$root.append($el);
}
$el.data('cmp', uid);
- $el.find('.from').text(formatTime(new Date(entry.s)));
- $el.find('.to-text').text(formatTime(new Date(entry.e)));
+ $el.find('.from').text(formatTime(cleanDate(entry.s)));
+ $el.find('.to-text').text(formatTime(cleanDate(entry.e)));
$el.find('.title').text(entry.title).attr('title', entry.title);
if (!SINGLE_LOCATION) {
$el.find('.location').text(entry.location);