Remove jQuery dependency, convert to vanilla JavaScript

This commit is contained in:
Russell Ballestrini 2025-12-22 18:34:35 -05:00
parent 4bc0c67e3a
commit 42241d79b7
6 changed files with 59 additions and 70 deletions

View file

@ -8,17 +8,12 @@ This project minimizes JavaScript usage, preferring pure CSS solutions where pos
- Use `<details>` elements for toggles instead of JS
- External SDKs loaded only when payment method is enabled
- No build step - vanilla JS only
- jQuery used minimally (legacy, being phased out)
- No jQuery - all vanilla JavaScript
## Static JavaScript Files
Located in `make_post_sell/static/js/`:
### jquery-3.6.0.min.js
- jQuery library (legacy dependency)
- Used by: Stripe card form, markdown preview
- Loaded via `snippets/optional-javascript.j2` and `snippets/stripe.j2`
### qrcode.min.js
- QRious library for QR code generation
- Used by: Crypto checkout page
@ -27,7 +22,7 @@ Located in `make_post_sell/static/js/`:
### custom.js
- Markdown preview functionality
- Functions: `previewAjax()`, `sendPreview()`
- Uses jQuery for AJAX calls to `/markup-editor-preview`
- Uses fetch API for AJAX calls to `/markup-editor-preview`
## Inline JavaScript by Template
@ -43,7 +38,7 @@ Located in `make_post_sell/static/js/`:
- Crypto wallets toggle (checkbox + localStorage)
- Theme preview for shop default theme radio buttons
- Note: Payment provider toggles now use pure CSS `<details>` elements
- Note: Payment provider toggles use pure CSS `<details>` elements
### user_settings.j2
**Purpose:** User theme preference sync
@ -80,7 +75,7 @@ Located in `make_post_sell/static/js/`:
- Loads Stripe.js SDK
- Creates Payment Element for card input
- Handles `stripe.confirmSetup()` flow
- Requires jQuery
- Uses vanilla JS with `DOMContentLoaded`
### snippets/analytics.j2
**Purpose:** Analytics tracking (optional)
@ -92,7 +87,7 @@ Located in `make_post_sell/static/js/`:
### snippets/optional-javascript.j2
**Purpose:** Optional JS loading
- Loads jQuery and custom.js async
- Loads custom.js async
- Used for markdown preview functionality
## External SDKs
@ -119,6 +114,5 @@ Pages work without JavaScript where possible:
## Future Improvements
- Remove jQuery dependency (replace with vanilla JS)
- Convert remaining checkbox toggles to `<details>` elements
- Consider removing Google Analytics option (privacy)

View file

@ -1,30 +1,52 @@
// post_preview
// previewTimer must live outside the functions.
// Markdown preview functionality (vanilla JS, no jQuery)
var previewTimer = null;
function previewAjax(textarea, div, show_raw = false){
// set div to raw textarea while waiting for remote Markdown rendering.
function previewAjax(textareaId, divId, show_raw = false) {
var textarea = document.getElementById(textareaId);
var div = document.getElementById(divId);
if (!textarea || !div) return;
// Show raw textarea content while waiting for server-rendered Markdown
if (show_raw) {
// bust HTML tags like <script> to prevent running evil code.
var busted_textarea = $('#'+textarea).val().replace(/&/g, '&amp;').replace(/</g,'&lt;');
$('#' + div).html('<span class="preview-raw-markup">'+busted_textarea+'</span>');
// Escape HTML tags to prevent XSS
var escaped = textarea.value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
div.innerHTML = '<span class="preview-raw-markup">' + escaped + '</span>';
}
// Debounce: clear previous timer and set new one
if (previewTimer) {
clearTimeout(previewTimer);
}
previewTimer = setTimeout(
function() { sendPreview( textarea, div); },
800
);
previewTimer = setTimeout(function() {
sendPreview(textareaId, divId);
}, 800);
}
function sendPreview(textarea, div){
$.ajaxSetup ({
cache: false
function sendPreview(textareaId, divId) {
var textarea = document.getElementById(textareaId);
var div = document.getElementById(divId);
if (!textarea || !div) return;
var formData = new FormData();
formData.append('data', textarea.value);
fetch('/markup-editor-preview', {
method: 'POST',
body: formData,
cache: 'no-store'
})
.then(function(response) {
return response.text();
})
.then(function(html) {
div.innerHTML = html;
})
.catch(function(error) {
console.error('Preview error:', error);
});
var url = '/markup-editor-preview';
var params = { 'data' : $('#'+textarea).val() };
$( '#' + div ).load( url, params );
}

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
jquery-3.6.0.min.js

View file

@ -1,2 +1 @@
<script async src="/static/js/jquery.min.js"></script>
<script async src="/static/js/custom.js"></script>

View file

@ -42,7 +42,6 @@
{% macro new_card() %}
<script src="/static/js/jquery.min.js"></script>
<script src="https://js.stripe.com/v3/"></script>
<form action="/billing/add-card?shop_id={{ request.shop.id }}" method="post" data-secret="{{ client_secret }}" id="payment-form">
{% include 'snippets/csrf.j2' %}
@ -51,13 +50,10 @@
<div id="payment-element">
<!-- Elements will create form elements here -->
</div>
<!--
-->
<a href="https://stripe.com/docs/security/stripe" target="_blank"><img class="stripe-initial-width" src="https://stripe.com/img/about/logos/badge/outline-dark.svg"></a>
<button class="green-button button-max-width stripe-save-button">&#128274; Save Card</button>
<!-- Used to display Element errors. -->
<div id="error-message" role="alert" class="bold-text"></div>
@ -66,49 +62,31 @@
</form>
<script>
//$(document).ready(function() {
$(function () {
document.addEventListener('DOMContentLoaded', function() {
var stripe = Stripe("{{ request.shop.stripe_public_api_key }}");
const options = {clientSecret: '{{ client_secret }}'};
var elements = stripe.elements(options);
var elements = stripe.elements({clientSecret: '{{ client_secret }}'});
// Create and mount the Payment Element
const paymentElement = elements.create('payment');
var paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
// confirm stripe payment method setup intent.
// Handle form submission
var form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
form.addEventListener('submit', async function(event) {
event.preventDefault();
const {error} = await stripe.confirmSetup({
//`Elements` instance that was used to create the Payment Element
elements,
var result = await stripe.confirmSetup({
elements: elements,
confirmParams: {
return_url: '{{ request.route_url("add-card", shop_id=request.shop.id) }}',
}
});
if (error) {
// This point will only be reached if there is an immediate error when
// confirming the payment. Show error to your customer (for example, payment
// details incomplete)
const messageContainer = document.querySelector('#error-message');
messageContainer.textContent = error.message;
} else {
// Your customer will be redirected to your `return_url`. For some payment
// methods like iDEAL, your customer will be redirected to an intermediate
// site first to authorize the payment, then redirected to the `return_url`.
if (result.error) {
document.getElementById('error-message').textContent = result.error.message;
}
// On success, customer is redirected to return_url
});
});
</script>
{% endmacro %}