Vendor Alpine, Flowbite and Datepicker bundles locally
Serve alpinejs 3.15.12, @alpinejs/mask 3.15.12, flowbite 2.4.1 and flowbite-datepicker 2.0.0 from games/static/js/ instead of jsdelivr, so pages (and browser tests) work without network access. Adds the StaticScript primitive for vendored UMD bundles, which cannot be loaded as ES modules. https://claude.ai/code/session_01BKurBhE3Qj25p7Bfsg7EeK
This commit is contained in:
@@ -59,6 +59,7 @@ from common.components.primitives import (
|
||||
SearchField,
|
||||
SimpleTable,
|
||||
Span,
|
||||
StaticScript,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableTd,
|
||||
@@ -112,6 +113,7 @@ __all__ = [
|
||||
"searchselect_selected",
|
||||
"SimpleTable",
|
||||
"Span",
|
||||
"StaticScript",
|
||||
"Label",
|
||||
"TableHeader",
|
||||
"TableRow",
|
||||
|
||||
@@ -554,6 +554,12 @@ def ExternalScript(url: str) -> SafeText:
|
||||
return mark_safe(f'<script src="{url}"></script>')
|
||||
|
||||
|
||||
def StaticScript(filename: str) -> SafeText:
|
||||
"""A plain (classic, non-module) `<script src=...>` tag for a static JS
|
||||
file — for vendored UMD bundles, which break inside module scope."""
|
||||
return mark_safe(f'<script src="{static("js/" + filename)}"></script>')
|
||||
|
||||
|
||||
def YearPicker(
|
||||
year: int | None = None,
|
||||
available_years: tuple[int, ...] = (),
|
||||
|
||||
+6
-3
@@ -309,9 +309,12 @@ def Page(
|
||||
f' <script src="{static("js/htmx-redirect-toast.js")}"></script>\n'
|
||||
f" {django_htmx_script(nonce=None)}\n"
|
||||
f' <link rel="stylesheet" href="{static("base.css")}" />\n'
|
||||
' <script src="https://cdn.jsdelivr.net/npm/flowbite@2.4.1/dist/flowbite.min.js"></script>\n'
|
||||
' <script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/mask@3.x.x/dist/cdn.min.js"></script>\n'
|
||||
' <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>\n'
|
||||
# Vendored bundles (flowbite 2.4.1, alpinejs/@alpinejs/mask 3.15.12) —
|
||||
# served locally so pages work offline (and in browser tests). The mask
|
||||
# plugin must load before Alpine core; both stay deferred.
|
||||
f' <script src="{static("js/flowbite.min.js")}"></script>\n'
|
||||
f' <script defer src="{static("js/alpine-mask.min.js")}"></script>\n'
|
||||
f' <script defer src="{static("js/alpine.min.js")}"></script>\n'
|
||||
f" {_THEME_FOUC_SCRIPT}\n"
|
||||
" </head>\n"
|
||||
)
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
(()=>{function x(n){n.directive("mask",(e,{value:l,expression:r},{effect:s,evaluateLater:i,cleanup:u})=>{let p=()=>r,f="";queueMicrotask(()=>{if(["function","dynamic"].includes(l)){let o=i(r);s(()=>{p=t=>{let c;return n.dontAutoEvaluateFunctions(()=>{o(d=>{c=typeof d=="function"?d(t):d},{scope:{$input:t,$money:M.bind({el:e})}})}),c},a(e,!1)})}else a(e,!1);if(e._x_model){e._x_model.get()!==e.value&&(e._x_model.get()===null&&e.value===""||e._x_model.set(e.value));let o=e._x_forceModelUpdate;e._x_forceModelUpdate=t=>{t=String(t);let c=p(t);c&&c!=="false"&&(t=m(c,t)),f=t,o(t),e._x_model.set(t)}}});let g=new AbortController;u(()=>{g.abort()}),e.addEventListener("input",()=>a(e),{signal:g.signal,capture:!0}),e.addEventListener("blur",()=>a(e,!1),{signal:g.signal});function a(o,t=!0){let c=o.value,d=p(c);if(!d||d==="false")return!1;if(f.length-o.value.length===1)return f=o.value;let h=()=>{f=o.value=m(d,c)};t?v(o,d,()=>{h()}):h()}}).before("model")}function v(n,e,l){let r=n.selectionStart,s=n.value;l();let i=s.slice(0,r),u=m(e,i).length;n.setSelectionRange(u,u)}var _={9:/[0-9]/,a:/[a-zA-Z]/,"*":/[a-zA-Z0-9]/};function m(n,e){let l=0,r=0,s="";for(;l<n.length&&r<e.length;){let i=n[l],u=e[r];i in _?(_[i].test(u)&&(s+=u,l++),r++):(s+=i,l++,i===e[r]&&r++)}return s}function M(n,e=".",l,r=2){if(n==="-")return"-";if(/^\D+$/.test(n))return"9";l==null&&(l=e===","?".":",");let s=(f,g)=>{let a="",o=0;for(let t=f.length-1;t>=0;t--)f[t]!==g&&(o===3?(a=f[t]+g+a,o=0):a=f[t]+a,o++);return a},i=n.startsWith("-")?"-":"",u=n.replaceAll(new RegExp(`[^0-9\\${e}]`,"g"),""),p=Array.from({length:u.split(e)[0].length}).fill("9").join("");return p=`${i}${s(p,l)}`,r>0&&n.includes(e)&&(p+=`${e}`+"9".repeat(r)),queueMicrotask(()=>{this.el.value.endsWith(e)||this.el.value[this.el.selectionStart-1]===e&&this.el.setSelectionRange(this.el.selectionStart-1,this.el.selectionStart-1)}),p}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(x)});})();
|
||||
Vendored
+5
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Vendored
+2
File diff suppressed because one or more lines are too long
@@ -13,17 +13,16 @@ from django.urls import reverse
|
||||
from django.utils.timezone import localtime
|
||||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from common.components import ExternalScript
|
||||
from common.components import StaticScript
|
||||
from common.layout import render_page
|
||||
from common.time import format_duration
|
||||
from games.models import Game, Platform, Purchase, Session
|
||||
from games.views.stats_content import stats_content
|
||||
from games.views.stats_data import compute_stats
|
||||
|
||||
# Flowbite-datepicker UMD bundle, hoisted into the stats pages for YearPicker.
|
||||
_STATS_SCRIPTS = ExternalScript(
|
||||
"https://cdn.jsdelivr.net/npm/flowbite-datepicker@2.0.0/dist/Datepicker.umd.min.js"
|
||||
)
|
||||
# Flowbite-datepicker UMD bundle (vendored, v2.0.0), hoisted into the stats
|
||||
# pages for YearPicker.
|
||||
_STATS_SCRIPTS = StaticScript("datepicker.umd.js")
|
||||
|
||||
|
||||
def model_counts(request: HttpRequest) -> dict[str, bool]:
|
||||
|
||||
Reference in New Issue
Block a user