diff options
| author | Simon Rettberg | 2025-07-25 16:44:53 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2025-07-25 16:44:53 +0200 |
| commit | bdd2d06844d1a0eb2a68235b582845c1de00229c (patch) | |
| tree | 3c652a1523bed4cc78795bf3b468b9b28a8dab72 | |
| parent | [roomplanner] Add type annotations, change falsable -> nullable (diff) | |
| download | slx-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.
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&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); |
