SpontaneousCMS/spontaneous

View on GitHub
application/js/field/file.js

Summary

Maintainability
F
3 days
Test Coverage
// console.log('Loading FileField...')
Spontaneous.Field.File = (function($, S) {
    var dom = S.Dom;
    var FileField = new JS.Class(Spontaneous.Field.String, {
        selected_files: false,

        initialize: function(dialogue, conflict) {
            this.blobs = [];
            this.callSuper();
        },
        currentValue: function() {
            var pending, v = this.get('value');
            if ((pending = v.__pending__)) {
                return pending.value;
            }
            return v;
        },

        currentFilename: function() {
            return this.currentValue().filename;
        },

        currentFilesize: function() {
            return this.currentValue().filesize;
        },

        currentEditValue: function() {
            var value, pending, ui, v = this.get('value');
            if ((pending = v.__pending__)) {
                return pending.value;
            }
            value = v.original;
            if ((ui = v.__ui__)) {
                value.path = value.src;
                value.src = ui.src;
            }
            return value;
        },

        preview: function() {
            Spontaneous.UploadManager.register(this);
            var self = this
, value = this.currentValue()
            , filename = this.currentFilename();
            var wrap = dom.div('.file-field');
            var dropper = dom.div('.file-drop');

            var stopEvent = function(event) {
                event.stopPropagation();
                event.preventDefault();
            };

            var drop = function(event) {
                stopEvent(event);
                dropper.removeClass('drop-active');
                var files = event.dataTransfer.files;

                if (files && files.length > 0) {
                    this.selected_files = files;
                    S.Ajax.test_field_versions(this.content, [this], this.upload_values.bind(this), this.upload_conflict.bind(this));
                }

                return false;
            }.bind(this);

            var drag_enter = function(event) {
                stopEvent(event);
                $(this).addClass('drop-active');
                return false;
            }.bind(dropper);

            var drag_over = function(event) {
                stopEvent(event);
                return false;
            }.bind(dropper);

            var drag_leave = function(event) {
                stopEvent(event);
                $(this).removeClass('drop-active');
                return false;
            }.bind(dropper);

            dropper.get(0).addEventListener('drop', drop, true);
            dropper.bind('dragenter', drag_enter).bind('dragover', drag_over).bind('dragleave', drag_leave);


            var filename_info = dom.div('.filename');
            var filesize_info = dom.div('.filesize');

            var set_info = function(href, filename, filesize) {
                filename_info.text(filename);
                if (filesize) {
                    filesize_info.text(parseFloat(filesize, 10).to_filesize());
                }
            };
            if (value) {
                set_info(value.html, this.currentFilename(), this.currentFilesize());
            }

            dropper.append(this.progress_bar().parent());

            wrap.append(dropper, filename_info, filesize_info);

            this.drop_target = dropper;
            this.value_wrap = wrap;

            return wrap;
        },
        upload_values: function() {
            var file = this.selected_files[0];
            S.UploadManager.replace(this, file);
        },
        upload_conflict: function(conflict_data) {
            var dialogue = new S.ConflictedFieldDialogue(this, conflict_data);
            dialogue.open();
        },
        unload: function() {
            this.input = null;
            this._progress_bar = null;
            this.freeBlobs();
            Spontaneous.UploadManager.unregister(this);
            this.callSuper();
        },
        freeBlobs: function() {
            this.blobs.forEach(function(url) {
                window.URL.revokeObjectURL(url);
            });
        },
        upload_complete: function(values) {
            this.set('value', values.processed_value);
            this.set_version(values.version);
            this.selected_files = null;
            this.disable_progress();
        },
        progress_bar: function() {
            if (!this._progress_bar) {
                var progress_outer = dom.div('.drop-upload-outer').hide();
                var progress_inner = dom.div('.drop-upload-inner').css('width', 0);
                progress_outer.append(progress_inner);
                this._progress_bar = progress_inner;
            }
            return this._progress_bar;
        },
        disable_progress: function() {
            this.progress_bar().parent().hide();
            this.drop_target.add(this.value_wrap).removeClass('uploading');
        },
        upload_progress: function(position, total) {
            if (!this.drop_target.hasClass('uploading')) {
                this.drop_target.add(this.value_wrap).addClass('uploading');
            }
            this.progress_bar().parent().show();
            this.progress_bar().css('width', ((position/total)*100) + '%');
        },
        is_file: function() {
            return true;
        },

        createObjectURL: function(file) {
            var url = window.URL.createObjectURL(file);
            this.blobs.push(url);
            return url;
        },

        edit: function() {
            var self = this;
            var wrap = dom.div('.file-field', {'style':'position:relative;'});
            var value = this.value();
            var input = this.input();
            var filename_info = dom.div('.filename');
            var filesize_info = dom.div('.filesize');
            var choose_files = dom.a('.choose').text('Choose file...');

            var set_info = function(filename, filesize) {
                filename_info.text(filename);
                if (filesize) {
                    filesize_info.text(parseFloat(filesize, 10).to_filesize());
                }
            };

            var files_selected = function(files) {
                if (files.length > 0) {
                    var file = files[0], url = this.createObjectURL(file);
                    this.selected_files = files;
                    this._edited_value = url;
                    set_info(File.filename(file), file.fileSize);
                }
            }.bind(this);

            var onchange = function() {
                var files = input[0].files;
                files_selected(files);
            }.bind(this);

            var onclick = function() {
                self.focus();
                input.trigger('click');
                return false;
            };

            input.change(onchange);

            var dropper = dom.div('.file-drop');

            dropper.add(choose_files).click(onclick);

            // dropper.append(filename_info, filesize_info)
            wrap.append(dropper);

            var stopEvent = function(event) {
                event.stopPropagation();
                event.preventDefault();
            };

            var drop = function(event) {
                stopEvent(event);
                dropper.removeClass('drop-active');
                var files = event.dataTransfer.files;
                files_selected(files);
                return false;
            }.bind(this);

            var drag_enter = function(event) {
                stopEvent(event);
                $(this).addClass('drop-active');
                return false;
            }.bind(dropper);

            var drag_over = function(event) {
                stopEvent(event);
                return false;
            }.bind(dropper);

            var drag_leave = function(event) {
                stopEvent(event);
                $(this).removeClass('drop-active');
                return false;
            }.bind(dropper);

            dropper.get(0).addEventListener('drop', drop, true);
            dropper.bind('dragenter', drag_enter).bind('dragover', drag_over).bind('dragleave', drag_leave);

            if (value) {
                var s = value.html.split('/'), filename = s[s.length - 1];
                set_info(filename, value.filesize);
            }
            wrap.append(input, choose_files, filename_info, filesize_info);


            return wrap;
        },

        filename: function(value) {
            var s = value.html.split('/'), filename = s[s.length - 1];
            return filename;
        },

        accept_mimetype: '*/*',
        generate_input: function() {
            return dom.input({'type':'file', 'name':this.form_name(), 'accept':this.accept_mimetype});
        },
        accepts_focus: false,
        // called by edit dialogue in order to begin the async upload of files
        save: function() {
            if (!this.selected_files) { return; }
            var files = this.selected_files;
            if (files && files.length > 0) {
                this.drop_target.addClass('uploading');
                this.progress_bar().parent().show();
                var file_data = new FormData();
                var file = files[0];
                S.UploadManager.replace(this, file);
            }
            this.selected_files = false;
        },
        is_modified: function() {
            var files = this.selected_files;
            return (files && files.length > 0);
        },
        original_value: function() {
            this.processed_value();
        },
        set_edited_value: function(value) {
            if (value === this.edited_value()) {
                // do nothing
            } else {
                this.selected_files = null;
                this.set('value', value);
            }
        },
        stringValue: function() {
            if (this.mark_cleared) {
                this.mark_cleared = false;
                return { name: this.form_name(), value: '' };
            }
            return false; // don't upload this field as text
        },

        mark_cleared: false,

        clear_file: function() {
            // this.set('value', {});
            this.mark_cleared = true;
            this.selected_files = null;
            this.mark_modified();
        }

    });
    return FileField;
})(jQuery, Spontaneous);