Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Bootstrap-Flask Demo Application</title>
<style>
    .handle {
        cursor: -webkit-grabbing;
        cursor: move;
    }
</style>
</head>
  <body>
    <input class="form-control" id="files" multiple="" name="files" required="" type="file">
<div id="files-selected" class="mb-3">
    <ul class="list-group very-first-parent nested-sortable h-200">
    </ul>
</div>
    <script src="https://cdn.jsdelivr.net/npm/dcraw"></script>
<script src="https://sortablejs.github.io/Sortable/Sortable.js"></script>
<script>
    var filesField;
    var filesSelected;
    document.addEventListener('DOMContentLoaded', function () {
        filesField = document.getElementById("files");
        filesSelected = document.getElementById("files-selected");
        filesField.addEventListener('change', function (e) {
            var files = e.target.files;
            var reader = [];
            var filenames = Array.from(files).map(file => file.name);
            filesSelected.querySelector('.very-first-parent').innerHTML = '';
            filenames.forEach((filename, index) => {
                // alert('file selected');
                var file = files[index];
                var li = document.createElement('li');
                li.className = 'list-group-item';
                li.innerHTML = `
                    <div class="d-flex align-items-center">
                        <i class="handle bi-arrows-move"></i>
                        <button type="button" class="btn btn-danger me-3 ms-3" onclick="dismiss(this)">
                            <span aria-hidden="true">&times;</span>
                        </button>
                        <span class="file-name">${filename}</span>
                        <!--spinner--><div class="spinner spinner-border ms-auto" role="status"><span class="visually-hidden">Loading...</span></div><!--/spinner-->
                    </div>
                    <ul class="list-group nested-sortable"></ul>
                    `;
                showPreview(file, li);
                filesSelected.querySelector('.very-first-parent').appendChild(li);
            });
            makeNestedSortable();
        });
    });
    function isImage(file) {
        const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
        return imageTypes.includes(file.type);
    }
    function isRawImage(file) {
        const rawImageExtensions = ['.nef', '.cr2', '.tiff'];
        return rawImageExtensions.some(ext => file.name.toLowerCase().endsWith(ext));
    }
    function isVideo(file) {
        const videoTypes = ['video/mp4', 'video/quicktime'];
        return videoTypes.includes(file.type);
    }
    function replaceSpinner(string_old, string_new) {
        return string_old.replace(/<!--spinner-->.*<!--\/spinner-->/gi, string_new)
    }
    function showPreview(file, li) {
        if (isImage(file)) {
            const reader = new FileReader();
            reader.onload = function (e) {
                li.innerHTML = replaceSpinner(li.innerHTML, `<img class="preview ms-auto" src="${e.target.result}" height="70" style="max-height: 70px;">`);
            };
            reader.readAsDataURL(file);
        } else if (isRawImage(file)) {
            // You can use a library like raw.js to decode raw images and show a preview
            const reader = new FileReader();
            reader.onload = (function (o) {
                return function (e) {
                    // Get the image file as a buffer
                    var buf = new Uint8Array(e.currentTarget.result);
                    // Get the RAW metadata
                    var metadata = dcraw(buf, { verbose: true, identify: true }).split('\n').filter(String);
                    // Extract the thumbnail
                    var thumbnail = dcraw(buf, { extractThumbnail: true });
                    // Create thumbnail
                    var blob = new Blob([thumbnail], { type: "image/jpeg" });
                    var urlCreator = window.URL || window.webkitURL;
                    var imageUrl = urlCreator.createObjectURL(blob);
                    li.innerHTML = replaceSpinner(li.innerHTML, `<img class="preview ms-auto" src="${imageUrl}" height="70" style="max-height: 70px;">`);
                };
            })(file);
            reader.readAsArrayBuffer(file);
        } else if (isVideo(file)) {
            li.innerHTML = replaceSpinner(li.innerHTML, `<video src="${URL.createObjectURL(file)}" class="ms-auto" controls height="70" style="max-height: 70px;"></video>`);
        } else {
            li.innerHTML = replaceSpinner(li.innerHTML, `<span class="preview ms-auto">Preview not available</span>`);
        }
    }
    function dismiss(target) {
        var li = target.closest('li');
        var fileToDelete = li.querySelector('span.file-name').textContent;
        var dt = new DataTransfer();
        Array.from(filesField.files).forEach((file, i) => {
            if (file.name !== fileToDelete)
                dt.items.add(file)
            filesField.files = dt.files // this will trigger a change event
        });
        li.remove();
    }
    function makeNestedSortable() {
        nestedSortables = [].slice.call(document.querySelectorAll('.nested-sortable'));
        console.log(nestedSortables.length);
        for (var i = 0; i < nestedSortables.length; i++) {
            new Sortable(nestedSortables[i], {
                group: 'nested',
                animation: 150,
                fallbackOnBody: true,
                // invertSwap: true,
                swapThreshold: 0.5
            });
        }
    }
</script>
  </body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers