Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
344 lines
10 KiB
Plaintext
Executable File
344 lines
10 KiB
Plaintext
Executable File
NAME
|
|
jQuery Extensions - RSpade framework extensions and overrides to jQuery
|
|
|
|
SYNOPSIS
|
|
// Standard click handler with automatic preventDefault
|
|
$('.btn').click(function(e) {
|
|
console.log('Button clicked');
|
|
});
|
|
|
|
// Escape hatch for native behavior (rare)
|
|
$('.nav-link').click_allow_default(function(e) {
|
|
analytics.track('click');
|
|
// Link navigation happens
|
|
});
|
|
|
|
// Other jQuery helpers
|
|
if ($('.element').exists()) { ... }
|
|
if ($('.element').is_in_viewport()) { ... }
|
|
$('.form').checkValidity();
|
|
|
|
DESCRIPTION
|
|
RSpade extends jQuery with utility methods and overrides default behaviors
|
|
to provide sensible defaults for modern web applications. The most significant
|
|
change is the .click() override that automatically calls e.preventDefault()
|
|
to prevent accidental page navigation and form submission.
|
|
|
|
Unlike vanilla jQuery where developers must remember to call preventDefault
|
|
in nearly every click handler, RSpade makes the correct behavior automatic.
|
|
This eliminates a common source of bugs where forgotten preventDefault calls
|
|
cause unwanted page reloads or navigation.
|
|
|
|
Philosophy:
|
|
- Prevent default is correct 95% of the time
|
|
- Escape hatch available for the 5% case
|
|
- Fail toward the safe behavior (no navigation)
|
|
- Make the common case trivial
|
|
|
|
CLICK OVERRIDE
|
|
|
|
.click(handler)
|
|
Attach click handler that automatically calls e.preventDefault()
|
|
|
|
This prevents:
|
|
- Link navigation (<a href>)
|
|
- Form submission (<button type="submit">)
|
|
- Default button actions
|
|
|
|
Usage:
|
|
$('.delete-btn').click(function(e) {
|
|
delete_record($(this).data('id'));
|
|
// No need for e.preventDefault() - automatic
|
|
});
|
|
|
|
$('a.modal-trigger').click(function(e) {
|
|
open_modal();
|
|
// Link won't navigate - preventDefault called
|
|
});
|
|
|
|
.click() (no handler)
|
|
Trigger click event - native behavior unchanged
|
|
|
|
Usage:
|
|
$('.hidden-button').click(); // Triggers click
|
|
|
|
.click_allow_default(handler)
|
|
Escape hatch for native click behavior without preventDefault
|
|
|
|
Use this ONLY when you explicitly need default browser behavior.
|
|
Examples: analytics tracking before navigation, conditional preventDefault
|
|
|
|
Usage:
|
|
$('.external-link').click_allow_default(function(e) {
|
|
analytics.track('external_click', this.href);
|
|
// Navigation happens after handler
|
|
});
|
|
|
|
$('button[type=submit]').click_allow_default(function(e) {
|
|
if (!validate_form()) {
|
|
e.preventDefault(); // Conditionally prevent
|
|
}
|
|
// Otherwise allows form submission
|
|
});
|
|
|
|
JQUERY HELPERS
|
|
|
|
Element Existence and State
|
|
|
|
.exists()
|
|
Returns true if jQuery selector matched any elements
|
|
|
|
if ($('.error-message').exists()) {
|
|
console.log('Error message present');
|
|
}
|
|
|
|
.is_visible()
|
|
Returns true if element is visible (not display:none or hidden)
|
|
|
|
if ($('.modal').is_visible()) {
|
|
$('.modal').fadeOut();
|
|
}
|
|
|
|
.is_in_dom()
|
|
Returns true if element exists in and is attached to the DOM
|
|
|
|
if ($('.dynamic-element').is_in_dom()) {
|
|
// Element is live in the page
|
|
}
|
|
|
|
.is_in_viewport()
|
|
Returns true if element is currently visible in the viewport
|
|
|
|
$('.lazy-image').each(function() {
|
|
if ($(this).is_in_viewport()) {
|
|
load_image($(this));
|
|
}
|
|
});
|
|
|
|
Scrolling
|
|
|
|
.scroll_up_to(speed = 0)
|
|
Scrolls page up to bring element into view if it's above viewport
|
|
|
|
$('.error-field').scroll_up_to(300);
|
|
|
|
Element Information
|
|
|
|
.tagname()
|
|
Returns lowercase tag name of element
|
|
|
|
if ($element.tagname() === 'a') {
|
|
// It's a link
|
|
}
|
|
|
|
.is_external()
|
|
Returns true if link href is external to current domain
|
|
Only works on <a> elements
|
|
|
|
if ($('a').is_external()) {
|
|
$(this).attr('target', '_blank');
|
|
}
|
|
|
|
Form Validation
|
|
|
|
.checkValidity()
|
|
Returns true if form/field passes HTML5 validation
|
|
|
|
if ($('form').checkValidity()) {
|
|
submit_form();
|
|
}
|
|
|
|
.reportValidity()
|
|
Triggers browser's native validation UI, returns validity
|
|
|
|
if (!$('form').reportValidity()) {
|
|
return; // Browser shows validation errors
|
|
}
|
|
|
|
.requestSubmit()
|
|
Programmatically submit form (triggers validation)
|
|
|
|
$('form').requestSubmit();
|
|
|
|
Focus Selector
|
|
|
|
:focus pseudo-selector
|
|
Select element that currently has focus
|
|
|
|
if ($('input').is(':focus')) {
|
|
// Input is focused
|
|
}
|
|
|
|
$('input:focus').addClass('active');
|
|
|
|
RSPADE VS VANILLA JQUERY
|
|
|
|
Click Handlers
|
|
|
|
Vanilla jQuery:
|
|
$('.btn').click(function(e) {
|
|
e.preventDefault(); // Must remember this
|
|
do_something();
|
|
});
|
|
|
|
RSpade:
|
|
$('.btn').click(function(e) {
|
|
do_something(); // preventDefault automatic
|
|
});
|
|
|
|
Existence Checks
|
|
|
|
Vanilla jQuery:
|
|
if ($('.element').length > 0) { ... }
|
|
|
|
RSpade:
|
|
if ($('.element').exists()) { ... }
|
|
|
|
Form Validation
|
|
|
|
Vanilla jQuery:
|
|
if ($('form')[0].checkValidity()) { ... }
|
|
|
|
RSpade:
|
|
if ($('form').checkValidity()) { ... }
|
|
|
|
WHEN TO USE .click_allow_default()
|
|
|
|
Valid use cases (rare):
|
|
|
|
1. Analytics tracking before navigation
|
|
$('a.external').click_allow_default(function(e) {
|
|
analytics.track('external_link');
|
|
// Let navigation happen
|
|
});
|
|
|
|
2. Conditional preventDefault
|
|
$('button[type=submit]').click_allow_default(function(e) {
|
|
if (!validate_form()) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
|
|
3. Progressive enhancement fallbacks
|
|
$('a[href="/fallback"]').click_allow_default(function(e) {
|
|
if (ajax_available()) {
|
|
e.preventDefault();
|
|
load_via_ajax();
|
|
}
|
|
// Otherwise let href work
|
|
});
|
|
|
|
Invalid use cases (use standard .click() instead):
|
|
|
|
- Opening modals (don't need navigation)
|
|
- Triggering actions (don't need navigation)
|
|
- Ajax requests (don't need navigation)
|
|
- Any case where you don't want the browser's default behavior
|
|
|
|
MIGRATION FROM VANILLA JQUERY
|
|
|
|
When porting jQuery code to RSpade:
|
|
|
|
1. Remove explicit preventDefault calls in click handlers
|
|
Before:
|
|
$('.btn').click(function(e) {
|
|
e.preventDefault();
|
|
do_action();
|
|
});
|
|
|
|
After:
|
|
$('.btn').click(function(e) {
|
|
do_action();
|
|
});
|
|
|
|
2. Identify legitimate native behavior needs
|
|
If you have click handlers that SHOULD allow navigation/submission,
|
|
switch to .click_allow_default()
|
|
|
|
3. Replace existence checks
|
|
Before: if ($('.el').length > 0)
|
|
After: if ($('.el').exists())
|
|
|
|
4. Replace form validation
|
|
Before: $('form')[0].checkValidity()
|
|
After: $('form').checkValidity()
|
|
|
|
EXAMPLES
|
|
|
|
Modal Trigger
|
|
// Opens modal without navigating
|
|
$('a.open-modal').click(function(e) {
|
|
const modal_id = $(this).data('modal');
|
|
$(`#${modal_id}`).fadeIn();
|
|
});
|
|
|
|
Delete Button
|
|
// Deletes record without form submission
|
|
$('.delete-btn').click(function(e) {
|
|
const id = $(this).data('id');
|
|
if (confirm('Delete this record?')) {
|
|
delete_record(id);
|
|
}
|
|
});
|
|
|
|
External Link with Tracking
|
|
// Tracks click then allows navigation
|
|
$('a.external').click_allow_default(function(e) {
|
|
analytics.track('external_link', {
|
|
url: this.href,
|
|
text: $(this).text()
|
|
});
|
|
});
|
|
|
|
Conditional Form Submit
|
|
// Only prevents submit if validation fails
|
|
$('form button[type=submit]').click_allow_default(function(e) {
|
|
if (!validate_custom_rules()) {
|
|
e.preventDefault();
|
|
show_errors();
|
|
}
|
|
});
|
|
|
|
Lazy Loading on Scroll
|
|
$(window).on('scroll', function() {
|
|
$('.lazy-image').each(function() {
|
|
if ($(this).is_in_viewport() && !$(this).data('loaded')) {
|
|
const src = $(this).data('src');
|
|
$(this).attr('src', src).data('loaded', true);
|
|
}
|
|
});
|
|
});
|
|
|
|
TROUBLESHOOTING
|
|
|
|
Problem: Links not navigating when they should
|
|
Solution: Use .click_allow_default() instead of .click()
|
|
|
|
Problem: Form submitting unexpectedly
|
|
Solution: This shouldn't happen - .click() prevents submission by default
|
|
If using .click_allow_default(), add explicit e.preventDefault()
|
|
|
|
Problem: .exists() not working
|
|
Solution: Ensure Rsx_Jq_Helpers is loaded - check browser console for errors
|
|
|
|
Problem: Want to use .on('click') to avoid preventDefault
|
|
Solution: Don't do this - it defeats the framework's safety. If you need
|
|
native behavior, use .click_allow_default() to make intent explicit
|
|
|
|
IMPLEMENTATION NOTES
|
|
|
|
The click override is implemented in:
|
|
/app/RSpade/Core/Js/Rsx_Jq_Helpers.js
|
|
|
|
Native jQuery .click() is preserved as:
|
|
$.fn._click_native()
|
|
|
|
The override applies to all elements, not just links and buttons. This is
|
|
intentional - preventDefault is harmless on elements without default actions
|
|
and ensures consistency across the codebase.
|
|
|
|
SEE ALSO
|
|
jqhtml.txt - JQHTML component system
|
|
controller.txt - Controller click handlers
|
|
error_handling.txt - JavaScript error patterns
|