Extract Rsx_Droppable into its own file
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
NAME
|
||||
File Drop Handler - Global drag-and-drop file interception system
|
||||
Droppable - Global drag-and-drop file interception system
|
||||
|
||||
SYNOPSIS
|
||||
Add class="rsx-droppable" to any element or component to receive
|
||||
dropped files via the file-drop event.
|
||||
|
||||
DESCRIPTION
|
||||
The RSpade framework provides a global file drop handler that intercepts
|
||||
all file drag-and-drop operations at the document level. This system
|
||||
routes dropped files to designated drop targets using CSS class-based
|
||||
Droppable is the RSX framework's global file drop system. It intercepts
|
||||
all file drag-and-drop operations at the document level and routes
|
||||
dropped files to designated drop targets using CSS class-based
|
||||
registration.
|
||||
|
||||
Unlike traditional HTML5 drag-and-drop which requires explicit event
|
||||
handlers on each element, this system provides:
|
||||
handlers on each element, Droppable provides:
|
||||
- Automatic visual feedback during file drags
|
||||
- Smart target selection (single vs multiple targets)
|
||||
- Cursor feedback indicating valid/invalid drop zones
|
||||
- Component event integration
|
||||
|
||||
The framework initializes this handler automatically during bootstrap.
|
||||
Droppable initializes automatically during framework bootstrap.
|
||||
No manual initialization is required.
|
||||
|
||||
CSS CLASSES
|
||||
@@ -111,7 +111,7 @@ FILE-DROP EVENT
|
||||
|
||||
FILE VALIDATION
|
||||
|
||||
Each widget is responsible for validating dropped files. The framework
|
||||
Each widget is responsible for validating dropped files. Droppable
|
||||
provides files without filtering. Common validation patterns:
|
||||
|
||||
By MIME Type:
|
||||
@@ -161,7 +161,7 @@ FILE VALIDATION
|
||||
|
||||
CURSOR FEEDBACK
|
||||
|
||||
The framework automatically sets dropEffect to control cursor appearance:
|
||||
Droppable automatically sets dropEffect to control cursor appearance:
|
||||
|
||||
- "copy" cursor: Shown when hovering over a valid drop target
|
||||
- "none" cursor: Shown when no valid target exists or when hovering
|
||||
@@ -172,12 +172,12 @@ CURSOR FEEDBACK
|
||||
IMPLEMENTATION NOTES
|
||||
|
||||
Drag Counter:
|
||||
The framework uses a drag counter to track when files enter and
|
||||
leave the window. This handles the common issue where dragenter
|
||||
and dragleave fire for child elements.
|
||||
Droppable uses a drag counter to track when files enter and leave
|
||||
the window. This handles the common issue where dragenter and
|
||||
dragleave fire for child elements.
|
||||
|
||||
Event Prevention:
|
||||
The handler prevents default browser behavior for all file drags,
|
||||
Droppable prevents default browser behavior for all file drags,
|
||||
ensuring files are never accidentally downloaded or opened.
|
||||
|
||||
Cleanup:
|
||||
@@ -276,7 +276,7 @@ STYLING RECOMMENDATIONS
|
||||
background: rgba(0, 123, 255, 0.15);
|
||||
}
|
||||
|
||||
RSX VS HTML5 DRAG-DROP
|
||||
DROPPABLE VS HTML5 DRAG-DROP
|
||||
|
||||
Standard HTML5:
|
||||
- Must add dragenter, dragover, drop handlers to each element
|
||||
@@ -284,9 +284,9 @@ RSX VS HTML5 DRAG-DROP
|
||||
- Must track drag state per element
|
||||
- No automatic multi-target coordination
|
||||
|
||||
RSX:
|
||||
Droppable:
|
||||
- Add rsx-droppable class, handle file-drop event
|
||||
- Framework handles all drag events
|
||||
- Droppable handles all drag events
|
||||
- Automatic state management and cleanup
|
||||
- Smart single vs multi-target behavior
|
||||
|
||||
@@ -315,4 +315,4 @@ SEE ALSO
|
||||
|
||||
VERSION
|
||||
RSpade Framework 1.0
|
||||
Last Updated: 2025-01-14
|
||||
Last Updated: 2026-01-15
|
||||
@@ -1330,6 +1330,7 @@ FUTURE DEVELOPMENT
|
||||
✓ Session-based attachment security with can_user_assign_this_file()
|
||||
✓ Attachment API (attach_to, add_to, detach)
|
||||
✓ Model helper methods (get_attachment, get_attachments)
|
||||
✓ Droppable - Global drag-and-drop file interception system
|
||||
|
||||
Planned Enhancements:
|
||||
|
||||
@@ -1367,7 +1368,7 @@ FUTURE DEVELOPMENT
|
||||
- Automatic cleanup of unused thumbnails
|
||||
|
||||
JQHTML Upload Widgets:
|
||||
- Drag-and-drop file uploader component
|
||||
✓ Droppable - Global drag-and-drop file interception (see droppable.txt)
|
||||
- Multi-file upload queue with progress
|
||||
- Image cropper/editor widget
|
||||
- Camera capture widget
|
||||
@@ -1426,10 +1427,11 @@ SECURITY
|
||||
they own or have permission to view.
|
||||
|
||||
SEE ALSO
|
||||
droppable.txt - Global drag-and-drop file interception system
|
||||
model.txt - Model system documentation
|
||||
storage_directories.txt - Storage directory conventions
|
||||
migrations.txt - Database migration system
|
||||
|
||||
VERSION
|
||||
RSpade Framework 1.0
|
||||
Last Updated: 2025-11-04
|
||||
Last Updated: 2026-01-15
|
||||
|
||||
@@ -385,6 +385,89 @@ DELETING FILES
|
||||
->where('fileable_id', $project_id)
|
||||
->delete();
|
||||
|
||||
DRAG-AND-DROP UPLOADS WITH DROPPABLE
|
||||
|
||||
Use Droppable to enable drag-and-drop file uploads in JQHTML components.
|
||||
See droppable.txt for full documentation.
|
||||
|
||||
Basic Integration:
|
||||
|
||||
Template (My_Uploader.jqhtml):
|
||||
|
||||
<Define:My_Uploader tag="div" class="rsx-droppable My_Uploader">
|
||||
<div class="drop-hint">Drop files here or click to upload</div>
|
||||
<input type="file" $sid="file_input" style="display: none" />
|
||||
<ul $sid="file_list"></ul>
|
||||
</Define:My_Uploader>
|
||||
|
||||
JavaScript (My_Uploader.js):
|
||||
|
||||
class My_Uploader extends Jqhtml_Component {
|
||||
on_render() {
|
||||
// Handle dropped files via Droppable
|
||||
this.on('file-drop', (_, data) => {
|
||||
this._upload_files(data.files);
|
||||
});
|
||||
|
||||
// Handle click-to-upload
|
||||
this.$.on('click', () => this.$sid('file_input').click());
|
||||
this.$sid('file_input').on('change', (e) => {
|
||||
this._upload_files(e.target.files);
|
||||
});
|
||||
}
|
||||
|
||||
async _upload_files(files) {
|
||||
for (let file of files) {
|
||||
// Validate
|
||||
if (file.size > 10 * 1024 * 1024) {
|
||||
Flash.error(`${file.name} exceeds 10 MB limit`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Upload
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const response = await $.ajax({
|
||||
url: '/_upload',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
this._add_to_list(response.attachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_add_to_list(attachment) {
|
||||
this.$sid('file_list').append(
|
||||
`<li>${attachment.file_name}</li>`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SCSS (My_Uploader.scss):
|
||||
|
||||
.My_Uploader {
|
||||
border: 2px dashed #ccc;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
&.rsx-drop-active {
|
||||
border-color: #007bff;
|
||||
background: rgba(0, 123, 255, 0.05);
|
||||
}
|
||||
|
||||
&.rsx-drop-target {
|
||||
border-style: solid;
|
||||
background: rgba(0, 123, 255, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
SECURITY CONSIDERATIONS
|
||||
|
||||
1. Always validate files:
|
||||
@@ -426,9 +509,10 @@ SECURITY CONSIDERATIONS
|
||||
|
||||
SEE ALSO
|
||||
file_upload.txt - Complete file upload system documentation
|
||||
droppable.txt - Global drag-and-drop file interception system
|
||||
model.txt - Model system documentation
|
||||
routing.txt - Route and endpoint documentation
|
||||
|
||||
VERSION
|
||||
RSpade Framework 1.0
|
||||
Last Updated: 2025-11-02
|
||||
Last Updated: 2026-01-15
|
||||
|
||||
Reference in New Issue
Block a user