Ring header restructured from flat 1fr/auto grid into two semantic rows: - Info row: title + badges left, progress counter right - Controls row: Reverse and Autoplay toggles right-aligned Now-playing row shows full title (no line-clamp truncation) and product thumbnail. JS reads og:image meta tag for current thumbnail during SPA navigation. SPA updates for edit button, download button, file info, comments, and canonical link. Footer and docs updates.
5.2 KiB
JavaScript Usage
This project minimizes JavaScript usage, preferring pure CSS solutions where possible (e.g., <details> elements for toggles). JavaScript is used only where necessary for payment integrations, real-time updates, and progressive enhancement.
Philosophy
- Prefer pure HTML/CSS over JavaScript
- Use
<details>elements for toggles instead of JS - External SDKs loaded only when payment method is enabled
- No build step - vanilla JS only
- No jQuery - all vanilla JavaScript
Static JavaScript Files
Located in make_post_sell/static/js/:
qrcode.min.js
- QRious library for QR code generation
- Used by: Crypto checkout page
- Generates payment QR codes for XMR/DOGE addresses
custom.js
- Markdown preview functionality
- Functions:
previewAjax(),sendPreview() - Uses fetch API for AJAX calls to
/markup-editor-preview
watch.js
- Watch mode continuous playback engine
- Used by:
product.j2when shop haswatch_mode_enabled - Discovery ring with deterministic content traversal per shop
- Crossfade transitions between media (3s, 60 steps)
- Countdown overlay (7s) between items
- Queue management: add, remove, reorder
- Two-phase preload: JSON metadata fetch, then media buffering 30s before end
- Recently-played filtering via localStorage (4-hour expiry)
- Handles video, audio, and static content (PDFs, images)
- Autoplay toggle persisted in localStorage
- Ring state (position, direction, history) persisted in localStorage
comments.js
- AJAX comment submission (progressive enhancement)
- Intercepts comment form POST, submits via
fetch()withX-Requested-With: XMLHttpRequest - Server returns JSON (HTTP 201) for AJAX requests
- Inserts new comment into DOM without page reload (preserves media playback)
- Falls back to normal POST + redirect without JS or on error
player.js
- Pop-out media player with draggable window
- Prev/next navigation and keyboard shortcuts
- Auto-advance for images/PDFs (60s timer)
- Preloads adjacent media for instant switching
- Used by:
/randomand/tvendpoints
Inline JavaScript by Template
base.j2
Purpose: Theme switching (dark/light mode)
- Runs immediately in
<head>to prevent flash of wrong theme - Priority: localStorage > user preference > shop default
- Exposes
window.setTheme()for programmatic use
shop_settings.j2
Purpose: Settings page interactions
- Crypto wallets toggle (checkbox + localStorage)
- Theme preview for shop default theme radio buttons
- Note: Payment provider toggles use pure CSS
<details>elements
user_settings.j2
Purpose: User theme preference sync
- Syncs theme radio buttons with localStorage
- Updates localStorage on form submit
cart_checkout.j2
Purpose: Payment processing
-
PayPal SDK (
paypal.Buttons())- Loads PayPal SDK from
paypal.com - Creates orders via
POST /paypal/create-order - Handles approval flow and form submission
- Double-click protection flags
- Loads PayPal SDK from
-
Cancel Crypto Quote (
cancelQuote())- Cancels pending crypto payment quotes
- Uses fetch API with CSRF token
crypto_checkout.j2
Purpose: Crypto payment monitoring
- QR code generation using QRious library
- Countdown timer for quote expiry
- Status polling via fetch API
- Copy-to-clipboard for address/amount
- Dynamic UI updates based on payment status
- Functions:
disableQuoteButtons(),removePaymentElements(),replaceButtonsWithInvoiceLink()
snippets/stripe.j2
Purpose: Stripe card form (macro new_card())
- Loads Stripe.js SDK
- Creates Payment Element for card input
- Handles
stripe.confirmSetup()flow - Uses vanilla JS with
DOMContentLoaded
snippets/analytics.j2
Purpose: Analytics tracking (optional)
- Plausible Analytics (privacy-focused)
- Google Analytics (gtag.js)
- Only loaded if shop has configured analytics
product.j2
Purpose: Inline video playback
playInline()replaces thumbnail container with<video>element on click- Used for preview playback on product pages without watch mode
- Loads
watch.jswhen shop haswatch_mode_enabled
snippets/comments.j2
Purpose: Comment form
- Loads
comments.jsasync for AJAX submission - Uses
js-onlyclass pattern for elements requiring JS
snippets/optional-javascript.j2
Purpose: Optional JS loading
- Loads custom.js async
- Used for markdown preview functionality
External SDKs
| SDK | URL | Used For |
|---|---|---|
| PayPal | paypal.com/sdk/js |
PayPal button/checkout |
| Stripe | js.stripe.com/v3/ |
Card payment form |
| Plausible | Shop-configured domain | Privacy analytics |
| Google Analytics | googletagmanager.com |
Google analytics |
CSRF Protection
All fetch/AJAX calls include CSRF tokens:
- Header:
X-CSRF-Token - Value from:
{{ request.session.get_csrf_token() }}or hidden input
Progressive Enhancement
Pages work without JavaScript where possible:
- Payment provider toggles use
<details>(pure CSS) - Forms submit normally without JS
- JS enhances UX (copy buttons, QR codes, live previews)
- Comment forms POST normally without JS; AJAX submission preserves playback with JS
- Watch mode elements use
js-onlyclass (hidden via<noscript>stylesheet) - Video thumbnails link directly to media without JS; inline playback with JS