eprothro
3/10/2017 - 11:22 PM

s3 direct upload.js

function DirectUploadInput($el) {
  var self = this;
  // The jquery obj for the input
  self.$el = $el;

  // Other object variables
  self.$form =          $el.closest('form');
  self.host =           $el.data('host')
  self.targetUrl =      $el.data('url');
  self.formData =       $el.data('form-data');
  self.$progressBar =   $("<div class='progress'></div>");
  self.$progressMeter = $("<div class='progress-meter'></div>");
  self.$targetUrl =     $('#' + $el.data('target-url-id'));
  self.$targetImage =   $('#' + $el.data('target-image-id'));
  self.$trigger =       $('#' + $el.data('trigger-id'));

  // Object functions to be called on object instantiation
  self.init();
}

DirectUploadInput.prototype = {
  constructor : DirectUploadInput,

    // Initializes the object state
    init : function() {
      // `self` used to maintain reference to this object, as
      // `this` will be in a different scope in jquery handlers
      var self = this;
      self.insertProgressBar();

      self.$el.fileupload({
        fileInput:       self.$el,
        url:             self.url,
        type:            'POST',
        autoUpload:       true,
        formData:         self.formData,
        paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
        dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
        replaceFileInput: false,
        add:              $.proxy(self.selectFile, self),
        progressall:      $.proxy(self.updateProgress, self),
        start:            $.proxy(self.beginUpload, self),
        done:             $.proxy(self.completeUpload, self),
        fail:             $.proxy(self.fail, self),
      });

      self.$trigger.click(function(e){
        if($(this).attr('disabled') == undefined && $(this).prop('disabled') != true){
          self.$el.click();
        }
      });
    },

    // Other functions to make object functional
    // modular, and reusable

    insertProgressBar : function() {
      var $barContainer = this.$progressBar.append(this.$progressMeter);
      $barContainer.hide();
      this.$el.after($barContainer);
    },

    selectFile : function(e, data){
      this.formData["Content-Type"] = data.files[0].type;
      data.formData = this.formData;=
      data.submit();
    },

    updateProgress : function(e, data){
      var progress = parseInt(data.loaded / data.total * 100, 10);
      this.$progressMeter.css('width', progress + '%')
    },

    disable : function(){
      if (this.$trigger.length > 0){
        // update attr for styling, prop for logic
        this.$trigger.attr('disabled', true).prop('disabled', true);
      }
      this.$el.attr('disabled', true).prop('disabled', true);
    },

    enable : function(){
      if (this.$trigger.length > 0){
        this.$trigger.attr('disabled', false).prop('disabled', false);
      }
      this.$el.attr('disabled', false).prop('disabled', false);
    },

    beginUpload : function (e) {
      this.disable();
      this.$progressBar.slideDown('fast');
      this.$progressBar.removeClass('alert warning secondary');
      this.$progressBar.addClass('success');
      this.$progressMeter.css('width', '0%');
    },

    completeUpload : function(e, data) {
      // extract key and generate URL from response
      var key   = $(data.jqXHR.responseXML).find("Key").text();
      var url   = window.location.protocol + '//' + this.host + '/' + key;

      this.$targetUrl.val(url);
      this.$targetImage.prop('src', url).removeClass('hide');
      this.enable();

      var self = this;
      setTimeout(function(){
        self.$progressBar.slideUp('fast');
      }, 500);
    },

    fail : function(){
      this.$progressBar.addClass('alert');
    }
}

$(document).ready(function(){
  $(".js-direct-upload-input").each( function() {
    console.log('direct upload input initialized');
    window.uploadInput = new DirectUploadInput($(this));
  });
});