- MPS-6: referrer analytics (domain, query, trend line charts) - MPS-7: sandbox mode creative filter system - MPS-8: user S3 bucket + artifact storage - MPS-9: shop S3 mirror bucket - architecture.md: system diagram, request flow, data pipeline, S3 layout - JAVASCRIPT.md: add sandbox.js, signals.js, MediaPipe SDK entries - sandbox-mode.md: mark S3 upload as implemented - mps-2.md: document referrer_domain + referrer_query columns Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
177 lines
6.4 KiB
Markdown
177 lines
6.4 KiB
Markdown
# 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.j2` when shop has `watch_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
|
|
|
|
### sandbox.js
|
|
- Client-side creative filter engine (IIFE, ~700 lines)
|
|
- Used by: `base.j2` when shop has `sandbox_mode` enabled
|
|
- 32 CSS filter presets across 7 categories (basic, warm, cool, dramatic, color, Instagram-style, SVG)
|
|
- 7 adjustment sliders (brightness, contrast, saturation, hue, blur, sepia, grayscale)
|
|
- Image export via canvas `toBlob()` (PNG)
|
|
- Video export via `MediaRecorder` + `captureStream(30fps)` (WebM)
|
|
- On-demand face detection via MediaPipe Face Mesh (468 landmarks, eye glow, face mask overlays)
|
|
- Upload-to-bucket: presigned POST to user's S3 bucket via `/u/sandbox/upload`
|
|
- localStorage persistence: preset, slider values, panel state, filter mode
|
|
- Exposes `window.sandboxReapply()` for watch.js SPA integration
|
|
|
|
### signals.js
|
|
- Anonymous page visit signal collector
|
|
- Used by: all product/content pages
|
|
- Collects presence (wall_clock, visible, active), scroll (depth, direction changes), and media playback signals
|
|
- Sends single JSON beacon (~300 bytes) via `navigator.sendBeacon()` on page unload
|
|
- No cookies, no IPs, no fingerprints — purely behavioral signals
|
|
- Viewport width sent for device class derivation (server-side)
|
|
|
|
### comments.js
|
|
- AJAX comment submission (progressive enhancement)
|
|
- Intercepts comment form POST, submits via `fetch()` with `X-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: `/random` and `/tv` endpoints
|
|
|
|
## 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
|
|
|
|
1. **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
|
|
|
|
2. **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.js` when shop has `watch_mode_enabled`
|
|
|
|
### snippets/comments.j2
|
|
**Purpose:** Comment form
|
|
|
|
- Loads `comments.js` async for AJAX submission
|
|
- Uses `js-only` class 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 |
|
|
| MediaPipe | `cdn.jsdelivr.net` | Face detection (sandbox mode, on-demand) |
|
|
|
|
## 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-only` class (hidden via `<noscript>` stylesheet)
|
|
- Video thumbnails link directly to media without JS; inline playback with JS
|