NodeBB/NodeBB

View on GitHub
public/src/modules/uploadHelpers.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict';


define('uploadHelpers', ['alerts'], function (alerts) {
    const uploadHelpers = {};

    uploadHelpers.init = function (options) {
        const formEl = options.uploadFormEl;
        if (!formEl.length) {
            return;
        }
        formEl.attr('action', config.relative_path + options.route);

        if (options.dragDropAreaEl) {
            uploadHelpers.handleDragDrop({
                container: options.dragDropAreaEl,
                callback: function (upload) {
                    uploadHelpers.ajaxSubmit({
                        uploadForm: formEl,
                        upload: upload,
                        callback: options.callback,
                    });
                },
            });
        }

        if (options.pasteEl) {
            uploadHelpers.handlePaste({
                container: options.pasteEl,
                callback: function (upload) {
                    uploadHelpers.ajaxSubmit({
                        uploadForm: formEl,
                        upload: upload,
                        callback: options.callback,
                    });
                },
            });
        }

        if (options.uploadBtnEl) {
            const fileInput = formEl.find('input[name="files[]"]');
            options.uploadBtnEl.on('click', function () {
                fileInput.trigger('click');
            });
            fileInput.on('change', function (e) {
                const files = (e.target || {}).files ||
                    ($(this).val() ? [{ name: $(this).val(), type: utils.fileMimeType($(this).val()) }] : null);
                if (files) {
                    uploadHelpers.ajaxSubmit({
                        uploadForm: formEl,
                        upload: {
                            files: files,
                            fileNames: Array.from(files).map(f => f.name),
                        },
                        callback: options.callback,
                    });
                }
            });
        }
    };

    uploadHelpers.handleDragDrop = function (options) {
        let draggingDocument = false;
        const postContainer = options.container;
        const drop = options.container.find('.imagedrop');

        postContainer.on('dragenter', function onDragEnter() {
            if (draggingDocument) {
                return;
            }
            drop.css('top', '0px');
            drop.css('height', postContainer.height() + 'px');
            drop.css('line-height', postContainer.height() + 'px');
            drop.show();

            drop.on('dragleave', function () {
                drop.hide();
                drop.off('dragleave');
            });
        });

        drop.on('drop', function onDragDrop(e) {
            e.preventDefault();
            const files = e.originalEvent.dataTransfer.files;

            if (files.length) {
                let formData;
                if (window.FormData) {
                    formData = new FormData();
                    for (var i = 0; i < files.length; ++i) {
                        formData.append('files[]', files[i], files[i].name);
                    }
                }
                options.callback({
                    files: files,
                    formData: formData,
                });
            }

            drop.hide();
            return false;
        });

        function cancel(e) {
            e.preventDefault();
            return false;
        }

        $(document)
            .off('dragstart')
            .on('dragstart', function () {
                draggingDocument = true;
            })
            .off('dragend')
            .on('dragend, mouseup', function () {
                draggingDocument = false;
            });

        drop.on('dragover', cancel);
        drop.on('dragenter', cancel);
    };

    uploadHelpers.handlePaste = function (options) {
        const container = options.container;
        container.on('paste', function (event) {
            const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
            const files = [];
            const fileNames = [];
            let formData = null;
            if (window.FormData) {
                formData = new FormData();
            }
            [].forEach.call(items, function (item) {
                const file = item.getAsFile();
                if (file) {
                    const fileName = utils.generateUUID() + '-' + file.name;
                    if (formData) {
                        formData.append('files[]', file, fileName);
                    }
                    files.push(file);
                    fileNames.push(fileName);
                }
            });

            if (files.length) {
                options.callback({
                    files: files,
                    fileNames: fileNames,
                    formData: formData,
                });
            }
        });
    };

    uploadHelpers.ajaxSubmit = function (options) {
        const files = [...options.upload.files];

        for (let i = 0; i < files.length; ++i) {
            const isImage = files[i].type.match(/image./);
            if ((isImage && !app.user.privileges['upload:post:image']) || (!isImage && !app.user.privileges['upload:post:file'])) {
                return alerts.error('[[error:no-privileges]]');
            }
            if (!app.user.isAdmin && files[i].size > parseInt(config.maximumFileSize, 10) * 1024) {
                options.uploadForm[0].reset();
                return alerts.error('[[error:file-too-big, ' + config.maximumFileSize + ']]');
            }
        }
        const alert_id = Date.now();
        options.uploadForm.off('submit').on('submit', function () {
            $(this).ajaxSubmit({
                headers: {
                    'x-csrf-token': config.csrf_token,
                },
                resetForm: true,
                clearForm: true,
                formData: options.upload.formData,
                error: function (xhr) {
                    let errorMsg = (xhr.responseJSON &&
                        (xhr.responseJSON.error || (xhr.responseJSON.status && xhr.responseJSON.status.message))) ||
                        '[[error:parse-error]]';

                    if (xhr && xhr.status === 413) {
                        errorMsg = xhr.statusText || 'Request Entity Too Large';
                    }
                    alerts.error(errorMsg);
                    alerts.remove(alert_id);
                },

                uploadProgress: function (event, position, total, percent) {
                    alerts.alert({
                        alert_id: alert_id,
                        message: '[[modules:composer.uploading, ' + percent + '%]]',
                    });
                },

                success: function (res) {
                    const uploads = res.response.images;
                    if (uploads && uploads.length) {
                        for (var i = 0; i < uploads.length; ++i) {
                            uploads[i].filename = files[i].name;
                            uploads[i].isImage = /image./.test(files[i].type);
                        }
                    }
                    options.callback(uploads);
                },

                complete: function () {
                    options.uploadForm[0].reset();
                    setTimeout(alerts.remove, 100, alert_id);
                },
            });

            return false;
        });

        options.uploadForm.submit();
    };

    return uploadHelpers;
});