Refine relative date/time; add docs to files
This commit is contained in:
parent
516a903565
commit
75680fae00
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal;
|
namespace MyPrayerJournal;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\Domain;
|
namespace MyPrayerJournal\Domain;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\Domain;
|
namespace MyPrayerJournal\Domain;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\Domain;
|
namespace MyPrayerJournal\Domain;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\Domain;
|
namespace MyPrayerJournal\Domain;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\Domain;
|
namespace MyPrayerJournal\Domain;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\Domain;
|
namespace MyPrayerJournal\Domain;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal;
|
namespace MyPrayerJournal;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\UI;
|
namespace MyPrayerJournal\UI;
|
||||||
|
|
||||||
@ -117,7 +123,7 @@ class Component
|
|||||||
$parsed = new DateTimeImmutable($date);
|
$parsed = new DateTimeImmutable($date);
|
||||||
$iso = $parsed->format('c');
|
$iso = $parsed->format('c');
|
||||||
$title = $parsed->setTimezone(new DateTimeZone($_REQUEST['time_zone']))->format('l, F j, Y \a\t g:ia T');
|
$title = $parsed->setTimezone(new DateTimeZone($_REQUEST['time_zone']))->format('l, F j, Y \a\t g:ia T');
|
||||||
return "<relative-date-time title=\"$title\" interval=5000>$iso</relative-date-time>";
|
return "<relative-date-time title=\"$title\" interval=10000>$iso</relative-date-time>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace MyPrayerJournal\UI;
|
namespace MyPrayerJournal\UI;
|
||||||
|
|
||||||
@ -56,7 +62,7 @@ class Layout
|
|||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
|
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
|
||||||
crossorigin=anonymous>
|
crossorigin=anonymous>
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet>
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel=stylesheet>
|
||||||
<link href=/style/style.css rel=stylesheet>
|
<link href=/_/style.css rel=stylesheet>
|
||||||
</head>
|
</head>
|
||||||
HEAD;
|
HEAD;
|
||||||
}
|
}
|
||||||
@ -136,18 +142,19 @@ class Layout
|
|||||||
rel=noopener>Developed</a> and hosted by
|
rel=noopener>Developed</a> and hosted by
|
||||||
<a href=https://bitbadger.solutions target=_blank rel=noopener>Bit Badger Solutions</a>
|
<a href=https://bitbadger.solutions target=_blank rel=noopener>Bit Badger Solutions</a>
|
||||||
</small></em>
|
</small></em>
|
||||||
<script src=https://unpkg.com/htmx.org@2.0.0 crossorigin=anonymous
|
<script src=https://unpkg.com/htmx.org@2.0.4 crossorigin=anonymous
|
||||||
integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw"></script>
|
integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+"></script>
|
||||||
<script>if (!htmx) document.write('<script src=\"/script/htmx.min.js\"><\/script>')</script>
|
<script>if (!htmx) document.write('<script src=\"/_/htmx.min.js\"><\/script>')</script>
|
||||||
<script async src=https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js
|
<script async src=https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js
|
||||||
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
|
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
|
||||||
crossorigin=anonymous></script>
|
crossorigin=anonymous></script>
|
||||||
<script>
|
<script>
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (!bootstrap) document.write('<script src=\"/script/bootstrap.bundle.min.js\"><\/script>')
|
if (!bootstrap) document.write('<script src=\"/_/bootstrap.bundle.min.js\"><\/script>')
|
||||||
}, 2000)
|
}, 2000)
|
||||||
</script>
|
</script>
|
||||||
<script src=/script/mpj.js></script>
|
<script src=/_/mpj.js></script>
|
||||||
|
<script src=/_/relative-date-time.js defer></script>
|
||||||
</footer><?php
|
</footer><?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace MyPrayerJournal\UI;
|
|
||||||
|
|
||||||
use DateTimeImmutable;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A type of relative date, along with the formatting strings
|
|
||||||
*/
|
|
||||||
enum RelativeDate: string
|
|
||||||
{
|
|
||||||
case LessThanXMinutes = 'less than a minute|less than %d minutes';
|
|
||||||
case XMinutes = 'a minute|%d minutes';
|
|
||||||
case AboutXHours = 'about an hour|about %d hours';
|
|
||||||
case XHours = 'an hour|%d hours';
|
|
||||||
case XDays = 'a day|%d days';
|
|
||||||
case AboutXWeeks = 'about a week|about %d weeks';
|
|
||||||
case XWeeks = 'a week|%d weeks';
|
|
||||||
case AboutXMonths = 'about a month|about %d months';
|
|
||||||
case XMonths = 'a month|%d months';
|
|
||||||
case AboutXYears = 'about a year|about %d years';
|
|
||||||
case XYears = 'a year|%d years';
|
|
||||||
case OverXYears = 'over a year|over %d years';
|
|
||||||
case AlmostXYears = 'almost a year|almost %d years';
|
|
||||||
|
|
||||||
// Many thanks to date-fns (https://date-fns.org) for this logic
|
|
||||||
/**
|
|
||||||
* Format the distance between two dates
|
|
||||||
*
|
|
||||||
* @param string|DateTimeImmutable $from The starting date/time
|
|
||||||
* @param string|DateTimeImmutable $to The ending date/time
|
|
||||||
* @return string The distance between two dates
|
|
||||||
* @throws Exception If date/time objects cannot be created
|
|
||||||
*/
|
|
||||||
public static function between(string|DateTimeImmutable $from, string|DateTimeImmutable $to): string
|
|
||||||
{
|
|
||||||
$aDay = 1_440.0;
|
|
||||||
$almost2Days = 2_520.0;
|
|
||||||
$aMonth = 43_200.0;
|
|
||||||
$twoMonths = 86_400.0;
|
|
||||||
|
|
||||||
$dtFrom = is_string($from) ? new DateTimeImmutable($from) : $from;
|
|
||||||
$dtTo = is_string($to) ? new DateTimeImmutable($to) : $to;
|
|
||||||
$minutes = abs($dtFrom->getTimestamp() - $dtTo->getTimestamp()) / 60;
|
|
||||||
$months = round($minutes / $aMonth);
|
|
||||||
$years = round($months / 12);
|
|
||||||
|
|
||||||
[$type, $number] = match (true) {
|
|
||||||
$minutes < 1.0 => [RelativeDate::LessThanXMinutes, 1],
|
|
||||||
$minutes < 45.0 => [RelativeDate::XMinutes, round($minutes)],
|
|
||||||
$minutes < 90.0 => [RelativeDate::AboutXHours, 1],
|
|
||||||
$minutes < $aDay => [RelativeDate::AboutXHours, round($minutes / 60)],
|
|
||||||
$minutes < $almost2Days => [RelativeDate::XDays, 1],
|
|
||||||
$minutes < $aMonth => [RelativeDate::XDays, round($minutes / $aDay)],
|
|
||||||
$minutes < $twoMonths => [RelativeDate::AboutXMonths, round($minutes / $aMonth)],
|
|
||||||
$months < 12 => [RelativeDate::XMonths, round($minutes / $aMonth)],
|
|
||||||
$months % 12 < 3 => [RelativeDate::AboutXYears, $years],
|
|
||||||
$months % 12 < 9 => [RelativeDate::OverXYears, $years],
|
|
||||||
default => [RelativeDate::AlmostXYears, $years]
|
|
||||||
};
|
|
||||||
[$singular, $plural] = explode('|', $type->value);
|
|
||||||
$value = $number == 1 ? $singular : sprintf($plural, $number);
|
|
||||||
return $dtFrom > $dtTo ? "$value ago" : "in $value";
|
|
||||||
}
|
|
||||||
}
|
|
1
src/public/_/htmx.min.js
vendored
Normal file
1
src/public/_/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
104
src/public/_/mpj.js
Normal file
104
src/public/_/mpj.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
/** myPrayerJournal script */
|
||||||
|
window.mpj = {
|
||||||
|
/**
|
||||||
|
* Show a message via toast
|
||||||
|
* @param {string} message The message to show
|
||||||
|
*/
|
||||||
|
showToast (message) {
|
||||||
|
const [level, msg] = message.split("|||")
|
||||||
|
|
||||||
|
let header
|
||||||
|
if (level !== "success") {
|
||||||
|
const heading = typ => `<span class="me-auto"><strong>${typ.toUpperCase()}</strong></span>`
|
||||||
|
|
||||||
|
header = document.createElement("div")
|
||||||
|
header.className = "toast-header"
|
||||||
|
header.innerHTML = heading(level === "warning" ? level : "error")
|
||||||
|
|
||||||
|
const close = document.createElement("button")
|
||||||
|
close.type = "button"
|
||||||
|
close.className = "btn-close"
|
||||||
|
close.setAttribute("data-bs-dismiss", "toast")
|
||||||
|
close.setAttribute("aria-label", "Close")
|
||||||
|
header.appendChild(close)
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = document.createElement("div")
|
||||||
|
body.className = "toast-body"
|
||||||
|
body.innerText = msg
|
||||||
|
|
||||||
|
const toastEl = document.createElement("div")
|
||||||
|
toastEl.className = `toast bg-${level === "error" ? "danger" : level} text-white`
|
||||||
|
toastEl.setAttribute("role", "alert")
|
||||||
|
toastEl.setAttribute("aria-live", "assertlive")
|
||||||
|
toastEl.setAttribute("aria-atomic", "true")
|
||||||
|
toastEl.addEventListener("hidden.bs.toast", e => e.target.remove())
|
||||||
|
if (header) toastEl.appendChild(header)
|
||||||
|
|
||||||
|
toastEl.appendChild(body)
|
||||||
|
document.getElementById("toasts").appendChild(toastEl)
|
||||||
|
new bootstrap.Toast(toastEl, { autohide: level === "success" }).show()
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Load local version of Bootstrap CSS if the CDN load failed
|
||||||
|
*/
|
||||||
|
ensureCss () {
|
||||||
|
let loaded = false
|
||||||
|
for (let i = 0; !loaded && i < document.styleSheets.length; i++) {
|
||||||
|
loaded = document.styleSheets[i].href.endsWith("bootstrap.min.css")
|
||||||
|
}
|
||||||
|
if (!loaded) {
|
||||||
|
const css = document.createElement("link")
|
||||||
|
css.rel = "stylesheet"
|
||||||
|
css.href = "/style/bootstrap.min.css"
|
||||||
|
document.getElementsByTagName("head")[0].appendChild(css)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** Script for the request edit component */
|
||||||
|
edit: {
|
||||||
|
/**
|
||||||
|
* Toggle the recurrence input fields
|
||||||
|
* @param {Event} e The click event
|
||||||
|
*/
|
||||||
|
toggleRecurrence ({ target }) {
|
||||||
|
const isDisabled = target.value === "Immediate"
|
||||||
|
;["recurCount", "recurInterval"].forEach(it => document.getElementById(it).disabled = isDisabled)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* The time zone of the current browser
|
||||||
|
* @type {string}
|
||||||
|
**/
|
||||||
|
timeZone: undefined,
|
||||||
|
/**
|
||||||
|
* Derive the time zone from the current browser
|
||||||
|
*/
|
||||||
|
deriveTimeZone () {
|
||||||
|
try {
|
||||||
|
this.timeZone = (new Intl.DateTimeFormat()).resolvedOptions().timeZone
|
||||||
|
} catch (_) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
htmx.on("htmx:afterOnLoad", function (evt) {
|
||||||
|
const hdrs = evt.detail.xhr.getAllResponseHeaders()
|
||||||
|
// Show a message if there was one in the response
|
||||||
|
if (hdrs.indexOf("x-toast") >= 0) {
|
||||||
|
mpj.showToast(evt.detail.xhr.getResponseHeader("x-toast"))
|
||||||
|
}
|
||||||
|
// Hide a modal window if requested
|
||||||
|
if (hdrs.indexOf("x-hide-modal") >= 0) {
|
||||||
|
document.getElementById(evt.detail.xhr.getResponseHeader("x-hide-modal") + "Dismiss").click()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
htmx.on("htmx:configRequest", function (evt) {
|
||||||
|
// Send the user's current time zone so that we can display local time
|
||||||
|
if (mpj.timeZone) {
|
||||||
|
evt.detail.headers["X-Time-Zone"] = mpj.timeZone
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mpj.deriveTimeZone()
|
121
src/public/_/relative-date-time.js
Normal file
121
src/public/_/relative-date-time.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relative Date/Time Custom HTML Element
|
||||||
|
*
|
||||||
|
* This creates an element that will take the existing date/time and replace it with words (ex. "about a year ago",
|
||||||
|
* "in 3 hours"). It will update based on the interval provided in the tag.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <relative-date-time interval=5000>2024-08-22T12:34:56+00:00</relative-date-time>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class RelativeDateTime extends HTMLElement {
|
||||||
|
|
||||||
|
static #LessThanXMinutes = Symbol()
|
||||||
|
static #XMinutes = Symbol()
|
||||||
|
static #AboutXHours = Symbol()
|
||||||
|
static #XDays = Symbol()
|
||||||
|
static #AboutXMonths = Symbol()
|
||||||
|
static #XMonths = Symbol()
|
||||||
|
static #AboutXYears = Symbol()
|
||||||
|
static #OverXYears = Symbol()
|
||||||
|
static #AlmostXYears = Symbol()
|
||||||
|
|
||||||
|
static #messages = new Map([
|
||||||
|
[RelativeDateTime.#LessThanXMinutes, ['less than a minute', 'less than %d minutes']],
|
||||||
|
[RelativeDateTime.#XMinutes, ['a minute', '%d minutes']],
|
||||||
|
[RelativeDateTime.#AboutXHours, ['about an hour', 'about %d hours']],
|
||||||
|
[RelativeDateTime.#XDays, ['a day', '%d days']],
|
||||||
|
[RelativeDateTime.#AboutXMonths, ['about a month', 'about %d months']],
|
||||||
|
[RelativeDateTime.#XMonths, ['a month', '%d months']],
|
||||||
|
[RelativeDateTime.#AboutXYears, ['about a year', 'about %d years']],
|
||||||
|
[RelativeDateTime.#OverXYears, ['over a year', 'over %d years']],
|
||||||
|
[RelativeDateTime.#AlmostXYears, ['almost a year', 'almost %d years']],
|
||||||
|
])
|
||||||
|
|
||||||
|
static #aDay = 1440.0
|
||||||
|
static #almost2Days = 2520.0
|
||||||
|
static #aMonth = 43200.0
|
||||||
|
static #twoMonths = 86400.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date, parsed from the `innerHTML` of the element
|
||||||
|
* @type Date
|
||||||
|
*/
|
||||||
|
#jsDate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the interval (set via `setTimeout`, passed to `clearTimeout`)
|
||||||
|
* @type ?number
|
||||||
|
*/
|
||||||
|
#timeOut = null
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
#update() {
|
||||||
|
|
||||||
|
const now = new Date()
|
||||||
|
const minutes = Math.abs((this.#jsDate.getTime() - now.getTime()) / 60 / 1000);
|
||||||
|
const months = Math.round(minutes / RelativeDateTime.#aMonth);
|
||||||
|
const years = Math.floor(months / 12);
|
||||||
|
|
||||||
|
/** @type symbol */
|
||||||
|
let typ
|
||||||
|
/** @type number */
|
||||||
|
let nbr
|
||||||
|
|
||||||
|
if (minutes < 1.0) {
|
||||||
|
typ = RelativeDateTime.#LessThanXMinutes
|
||||||
|
nbr = 1
|
||||||
|
} else if (minutes < 45.0) {
|
||||||
|
typ = RelativeDateTime.#XMinutes
|
||||||
|
nbr = Math.round(minutes)
|
||||||
|
} else if (minutes < 90.0) {
|
||||||
|
typ = RelativeDateTime.#AboutXHours
|
||||||
|
nbr = 1
|
||||||
|
} else if (minutes < RelativeDateTime.#aDay) {
|
||||||
|
typ = RelativeDateTime.#AboutXHours
|
||||||
|
nbr = Math.round(minutes / 60)
|
||||||
|
} else if (minutes < RelativeDateTime.#almost2Days) {
|
||||||
|
typ = RelativeDateTime.#XDays
|
||||||
|
nbr = 1
|
||||||
|
} else if (minutes < RelativeDateTime.#aMonth) {
|
||||||
|
typ = RelativeDateTime.#XDays
|
||||||
|
nbr = Math.round(minutes / RelativeDateTime.#aDay)
|
||||||
|
} else if (minutes < RelativeDateTime.#twoMonths) {
|
||||||
|
typ = RelativeDateTime.#AboutXMonths
|
||||||
|
nbr = Math.round(minutes / RelativeDateTime.#aMonth)
|
||||||
|
} else if (months < 12) {
|
||||||
|
typ = RelativeDateTime.#XMonths
|
||||||
|
nbr = Math.round(minutes / RelativeDateTime.#aMonth)
|
||||||
|
} else if (months % 12 < 3) {
|
||||||
|
typ = RelativeDateTime.#AboutXYears
|
||||||
|
nbr = years
|
||||||
|
} else if (months % 12 < 9) {
|
||||||
|
typ = RelativeDateTime.#OverXYears
|
||||||
|
nbr = years
|
||||||
|
} else {
|
||||||
|
typ = RelativeDateTime.#AlmostXYears
|
||||||
|
nbr = years + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const tmpl = RelativeDateTime.#messages.get(typ)
|
||||||
|
const message = nbr === 1 ? tmpl[0] : tmpl[1].replace("%d", nbr.toString())
|
||||||
|
this.innerText = this.#jsDate < now ? `${message} ago` : `in ${message}`
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.#jsDate = new Date(this.innerText)
|
||||||
|
this.#update()
|
||||||
|
this.#timeOut = setInterval(() => this.#update(), parseInt(this.getAttribute("interval")))
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
if (this.#timeOut) clearInterval(this.#timeOut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("relative-date-time", RelativeDateTime)
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
use MyPrayerJournal\UI\Component;
|
use MyPrayerJournal\UI\Component;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\Layout;
|
use MyPrayerJournal\UI\Layout;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\{Component, Layout};
|
use MyPrayerJournal\UI\{Component, Layout};
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\Layout;
|
use MyPrayerJournal\UI\Layout;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\Layout;
|
use MyPrayerJournal\UI\Layout;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\Component;use MyPrayerJournal\UI\Layout;
|
use MyPrayerJournal\UI\Component;use MyPrayerJournal\UI\Layout;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
use MyPrayerJournal\UI\{Component, Layout};
|
use MyPrayerJournal\UI\{Component, Layout};
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\Layout;
|
use MyPrayerJournal\UI\Layout;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\UI\{Component, Layout};
|
use MyPrayerJournal\UI\{Component, Layout};
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use BitBadger\InspiredByFSharp\Option;
|
use BitBadger\InspiredByFSharp\Option;
|
||||||
use BitBadger\PDODocument\RemoveFields;
|
use BitBadger\PDODocument\RemoveFields;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
use MyPrayerJournal\Domain\{RecurrencePeriod, Request, RequestAction};
|
use MyPrayerJournal\Domain\{RecurrencePeriod, Request, RequestAction};
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Domain\{History, Note, RequestAction};
|
use MyPrayerJournal\Domain\{History, Note, RequestAction};
|
||||||
use MyPrayerJournal\UI\{Layout, RelativeDate};
|
use MyPrayerJournal\UI\{Component, Layout};
|
||||||
|
|
||||||
require '../../start.php';
|
require '../../start.php';
|
||||||
|
|
||||||
@ -28,7 +34,7 @@ Layout::pageHead('Full Request');?>
|
|||||||
<h6 class="card-subtitle text-muted mb-2"><?php
|
<h6 class="card-subtitle text-muted mb-2"><?php
|
||||||
if (!is_null($answered)) { ?>
|
if (!is_null($answered)) { ?>
|
||||||
Answered <?=$answered->format('F j, Y')?>
|
Answered <?=$answered->format('F j, Y')?>
|
||||||
(<?=RelativeDate::between('now', $req->history[0]->asOf);?>) •<?php
|
(<?=Component::relativeDate($req->history[0]->asOf)?>) •<?php
|
||||||
} ?>
|
} ?>
|
||||||
Prayed <?=number_format($prayed)?> times • Open <?=number_format($daysOpen)?> days
|
Prayed <?=number_format($prayed)?> times • Open <?=number_format($daysOpen)?> days
|
||||||
</h6>
|
</h6>
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use BitBadger\PDODocument\Patch;
|
use BitBadger\PDODocument\Patch;
|
||||||
use MyPrayerJournal\Table;
|
use MyPrayerJournal\Table;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use BitBadger\PDODocument\Patch;
|
use BitBadger\PDODocument\Patch;
|
||||||
use MyPrayerJournal\Table;
|
use MyPrayerJournal\Table;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use BitBadger\InspiredByFSharp\Option;
|
use BitBadger\InspiredByFSharp\Option;
|
||||||
use BitBadger\PDODocument\{Document, Patch, RemoveFields};
|
use BitBadger\PDODocument\{Document, Patch, RemoveFields};
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use BitBadger\PDODocument\RemoveFields;
|
use BitBadger\PDODocument\RemoveFields;
|
||||||
use MyPrayerJournal\Table;
|
use MyPrayerJournal\Table;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use BitBadger\PDODocument\Patch;
|
use BitBadger\PDODocument\Patch;
|
||||||
use MyPrayerJournal\Table;
|
use MyPrayerJournal\Table;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
use MyPrayerJournal\Domain\Request;
|
use MyPrayerJournal\Domain\Request;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
use MyPrayerJournal\Domain\Request;
|
use MyPrayerJournal\Domain\Request;
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
use MyPrayerJournal\Domain\Request;
|
use MyPrayerJournal\Domain\Request;
|
||||||
|
1
src/public/script/htmx.min.js
vendored
1
src/public/script/htmx.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,213 +0,0 @@
|
|||||||
"use strict"
|
|
||||||
|
|
||||||
/** myPrayerJournal script */
|
|
||||||
window.mpj = {
|
|
||||||
/**
|
|
||||||
* Show a message via toast
|
|
||||||
* @param {string} message The message to show
|
|
||||||
*/
|
|
||||||
showToast (message) {
|
|
||||||
const [level, msg] = message.split("|||")
|
|
||||||
|
|
||||||
let header
|
|
||||||
if (level !== "success") {
|
|
||||||
const heading = typ => `<span class="me-auto"><strong>${typ.toUpperCase()}</strong></span>`
|
|
||||||
|
|
||||||
header = document.createElement("div")
|
|
||||||
header.className = "toast-header"
|
|
||||||
header.innerHTML = heading(level === "warning" ? level : "error")
|
|
||||||
|
|
||||||
const close = document.createElement("button")
|
|
||||||
close.type = "button"
|
|
||||||
close.className = "btn-close"
|
|
||||||
close.setAttribute("data-bs-dismiss", "toast")
|
|
||||||
close.setAttribute("aria-label", "Close")
|
|
||||||
header.appendChild(close)
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = document.createElement("div")
|
|
||||||
body.className = "toast-body"
|
|
||||||
body.innerText = msg
|
|
||||||
|
|
||||||
const toastEl = document.createElement("div")
|
|
||||||
toastEl.className = `toast bg-${level === "error" ? "danger" : level} text-white`
|
|
||||||
toastEl.setAttribute("role", "alert")
|
|
||||||
toastEl.setAttribute("aria-live", "assertlive")
|
|
||||||
toastEl.setAttribute("aria-atomic", "true")
|
|
||||||
toastEl.addEventListener("hidden.bs.toast", e => e.target.remove())
|
|
||||||
if (header) toastEl.appendChild(header)
|
|
||||||
|
|
||||||
toastEl.appendChild(body)
|
|
||||||
document.getElementById("toasts").appendChild(toastEl)
|
|
||||||
new bootstrap.Toast(toastEl, { autohide: level === "success" }).show()
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Load local version of Bootstrap CSS if the CDN load failed
|
|
||||||
*/
|
|
||||||
ensureCss () {
|
|
||||||
let loaded = false
|
|
||||||
for (let i = 0; !loaded && i < document.styleSheets.length; i++) {
|
|
||||||
loaded = document.styleSheets[i].href.endsWith("bootstrap.min.css")
|
|
||||||
}
|
|
||||||
if (!loaded) {
|
|
||||||
const css = document.createElement("link")
|
|
||||||
css.rel = "stylesheet"
|
|
||||||
css.href = "/style/bootstrap.min.css"
|
|
||||||
document.getElementsByTagName("head")[0].appendChild(css)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/** Script for the request edit component */
|
|
||||||
edit: {
|
|
||||||
/**
|
|
||||||
* Toggle the recurrence input fields
|
|
||||||
* @param {Event} e The click event
|
|
||||||
*/
|
|
||||||
toggleRecurrence ({ target }) {
|
|
||||||
const isDisabled = target.value === "Immediate"
|
|
||||||
;["recurCount", "recurInterval"].forEach(it => document.getElementById(it).disabled = isDisabled)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The time zone of the current browser
|
|
||||||
* @type {string}
|
|
||||||
**/
|
|
||||||
timeZone: undefined,
|
|
||||||
/**
|
|
||||||
* Derive the time zone from the current browser
|
|
||||||
*/
|
|
||||||
deriveTimeZone () {
|
|
||||||
try {
|
|
||||||
this.timeZone = (new Intl.DateTimeFormat()).resolvedOptions().timeZone
|
|
||||||
} catch (_) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
htmx.on("htmx:afterOnLoad", function (evt) {
|
|
||||||
const hdrs = evt.detail.xhr.getAllResponseHeaders()
|
|
||||||
// Show a message if there was one in the response
|
|
||||||
if (hdrs.indexOf("x-toast") >= 0) {
|
|
||||||
mpj.showToast(evt.detail.xhr.getResponseHeader("x-toast"))
|
|
||||||
}
|
|
||||||
// Hide a modal window if requested
|
|
||||||
if (hdrs.indexOf("x-hide-modal") >= 0) {
|
|
||||||
document.getElementById(evt.detail.xhr.getResponseHeader("x-hide-modal") + "Dismiss").click()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
htmx.on("htmx:configRequest", function (evt) {
|
|
||||||
// Send the user's current time zone so that we can display local time
|
|
||||||
if (mpj.timeZone) {
|
|
||||||
evt.detail.headers["X-Time-Zone"] = mpj.timeZone
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
mpj.deriveTimeZone()
|
|
||||||
|
|
||||||
class RelativeDateTime extends HTMLElement {
|
|
||||||
static observedAttributes = ["interval"]
|
|
||||||
|
|
||||||
static #LessThanXMinutes = Symbol()
|
|
||||||
static #XMinutes = Symbol()
|
|
||||||
static #AboutXHours = Symbol()
|
|
||||||
static #XDays = Symbol()
|
|
||||||
static #AboutXMonths = Symbol()
|
|
||||||
static #XMonths = Symbol()
|
|
||||||
static #AboutXYears = Symbol()
|
|
||||||
static #OverXYears = Symbol()
|
|
||||||
static #AlmostXYears = Symbol()
|
|
||||||
|
|
||||||
static #messages = new Map([
|
|
||||||
[RelativeDateTime.#LessThanXMinutes, ['less than a minute', 'less than %d minutes']],
|
|
||||||
[RelativeDateTime.#XMinutes, ['a minute', '%d minutes']],
|
|
||||||
[RelativeDateTime.#AboutXHours, ['about an hour', 'about %d hours']],
|
|
||||||
[RelativeDateTime.#XDays, ['a day', '%d days']],
|
|
||||||
[RelativeDateTime.#AboutXMonths, ['about a month', 'about %d months']],
|
|
||||||
[RelativeDateTime.#XMonths, ['a month', '%d months']],
|
|
||||||
[RelativeDateTime.#AboutXYears, ['about a year', 'about %d years']],
|
|
||||||
[RelativeDateTime.#OverXYears, ['over a year', 'over %d years']],
|
|
||||||
[RelativeDateTime.#AlmostXYears, ['almost a year', 'almost %d years']],
|
|
||||||
])
|
|
||||||
|
|
||||||
static #aDay = 1440.0
|
|
||||||
static #almost2Days = 2520.0
|
|
||||||
static #aMonth = 43200.0
|
|
||||||
static #twoMonths = 86400.0
|
|
||||||
|
|
||||||
/** @type Date The date/time for this relative date */
|
|
||||||
#jsDate
|
|
||||||
/** @type ?number The interval timer for this element */
|
|
||||||
#timeOut = null
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
#update() {
|
|
||||||
|
|
||||||
const now = new Date()
|
|
||||||
const minutes = Math.abs((this.#jsDate.getTime() - now.getTime()) / 60 / 1000);
|
|
||||||
const months = Math.round(minutes / RelativeDateTime.#aMonth);
|
|
||||||
const years = Math.floor(months / 12);
|
|
||||||
|
|
||||||
/** @type symbol */
|
|
||||||
let typ
|
|
||||||
/** @type number */
|
|
||||||
let nbr
|
|
||||||
|
|
||||||
if (minutes < 1.0) {
|
|
||||||
typ = RelativeDateTime.#LessThanXMinutes
|
|
||||||
nbr = 1
|
|
||||||
} else if (minutes < 45.0) {
|
|
||||||
typ = RelativeDateTime.#XMinutes
|
|
||||||
nbr = Math.round(minutes)
|
|
||||||
} else if (minutes < 90.0) {
|
|
||||||
typ = RelativeDateTime.#AboutXHours
|
|
||||||
nbr = 1
|
|
||||||
} else if (minutes < RelativeDateTime.#aDay) {
|
|
||||||
typ = RelativeDateTime.#AboutXHours
|
|
||||||
nbr = Math.round(minutes / 60)
|
|
||||||
} else if (minutes < RelativeDateTime.#almost2Days) {
|
|
||||||
typ = RelativeDateTime.#XDays
|
|
||||||
nbr = 1
|
|
||||||
} else if (minutes < RelativeDateTime.#aMonth) {
|
|
||||||
typ = RelativeDateTime.#XDays
|
|
||||||
nbr = Math.round(minutes / RelativeDateTime.#aDay)
|
|
||||||
} else if (minutes < RelativeDateTime.#twoMonths) {
|
|
||||||
typ = RelativeDateTime.#AboutXMonths
|
|
||||||
nbr = Math.round(minutes / RelativeDateTime.#aMonth)
|
|
||||||
} else if (months < 12) {
|
|
||||||
typ = RelativeDateTime.#XMonths
|
|
||||||
nbr = Math.round(minutes / RelativeDateTime.#aMonth)
|
|
||||||
} else if (months % 12 < 3) {
|
|
||||||
typ = RelativeDateTime.#AboutXYears
|
|
||||||
nbr = years
|
|
||||||
} else if (months % 12 < 9) {
|
|
||||||
typ = RelativeDateTime.#OverXYears
|
|
||||||
nbr = years
|
|
||||||
} else {
|
|
||||||
typ = RelativeDateTime.#AlmostXYears
|
|
||||||
nbr = years + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
const tmpl = RelativeDateTime.#messages.get(typ)
|
|
||||||
const message = nbr === 1 ? tmpl[0] : tmpl[1].replace("%d", nbr.toString())
|
|
||||||
this.innerText = this.#jsDate < now ? `${message} ago` : `in ${message}`
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
this.#jsDate = new Date(this.innerText)
|
|
||||||
this.#update()
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
if (this.#timeOut) clearInterval(this.#timeOut)
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeChangedCallback(name, oldValue, newValue) {
|
|
||||||
if (this.#timeOut) clearInterval(this.#timeOut)
|
|
||||||
if (this.#jsDate) this.#update()
|
|
||||||
this.#timeOut = setInterval(() => this.#update, parseInt(newValue))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("relative-date-time", RelativeDateTime)
|
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use MyPrayerJournal\Auth;
|
use MyPrayerJournal\Auth;
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<?php declare(strict_types=1);
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Auth0\SDK\Exception\ConfigurationException;
|
use Auth0\SDK\Exception\ConfigurationException;
|
||||||
use BitBadger\PDODocument\{AutoId, Configuration, Definition, DocumentException};
|
use BitBadger\PDODocument\{AutoId, Configuration, Definition, DocumentException};
|
||||||
@ -72,8 +78,7 @@ function hide_modal(string $name): void
|
|||||||
* @param array $methods The allowable HTTP methods
|
* @param array $methods The allowable HTTP methods
|
||||||
* @param bool $redirect Whether to redirect not-logged-on users (optional, defaults to true)
|
* @param bool $redirect Whether to redirect not-logged-on users (optional, defaults to true)
|
||||||
* @return Request The request (failures will not return)
|
* @return Request The request (failures will not return)
|
||||||
* @throws ConfigurationException If any is encountered
|
* @throws ConfigurationException|DocumentException If any is encountered
|
||||||
* @throws DocumentException If any is encountered
|
|
||||||
*/
|
*/
|
||||||
function validate_request(string $id, array $methods, bool $redirect = true): Request
|
function validate_request(string $id, array $methods, bool $redirect = true): Request
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user