github.com/apremalal/vamps-core@v1.0.1-0.20161221121535-d430b56ec174/server/webapps/app/base/plugins/jquery-file-upload/js/jquery.fileupload-ui.js (about)

     1  /*
     2   * jQuery File Upload User Interface Plugin 9.6.0
     3   * https://github.com/blueimp/jQuery-File-Upload
     4   *
     5   * Copyright 2010, Sebastian Tschan
     6   * https://blueimp.net
     7   *
     8   * Licensed under the MIT license:
     9   * http://www.opensource.org/licenses/MIT
    10   */
    11  
    12  /* jshint nomen:false */
    13  /* global define, window */
    14  
    15  (function (factory) {
    16      'use strict';
    17      if (typeof define === 'function' && define.amd) {
    18          // Register as an anonymous AMD module:
    19          define([
    20              'jquery',
    21              'tmpl',
    22              './jquery.fileupload-image.js',
    23              './jquery.fileupload-audio',
    24              './jquery.fileupload-video',
    25              './jquery.fileupload-validate'
    26          ], factory);
    27      } else {
    28          // Browser globals:
    29          factory(
    30              window.jQuery,
    31              window.tmpl
    32          );
    33      }
    34  }(function ($, tmpl) {
    35      'use strict';
    36  
    37      $.blueimp.fileupload.prototype._specialOptions.push(
    38          'filesContainer',
    39          'uploadTemplateId',
    40          'downloadTemplateId'
    41      );
    42  
    43      // The UI version extends the file upload widget
    44      // and adds complete user interface interaction:
    45      $.widget('blueimp.fileupload', $.blueimp.fileupload, {
    46  
    47          options: {
    48              // By default, files added to the widget are uploaded as soon
    49              // as the user clicks on the start buttons. To enable automatic
    50              // uploads, set the following option to true:
    51              autoUpload: false,
    52              // The ID of the upload template:
    53              uploadTemplateId: 'template-upload',
    54              // The ID of the download template:
    55              downloadTemplateId: 'template-download',
    56              // The container for the list of files. If undefined, it is set to
    57              // an element with class "files" inside of the widget element:
    58              filesContainer: undefined,
    59              // By default, files are appended to the files container.
    60              // Set the following option to true, to prepend files instead:
    61              prependFiles: false,
    62              // The expected data type of the upload response, sets the dataType
    63              // option of the $.ajax upload requests:
    64              dataType: 'json',
    65              
    66              // Error and info messages:
    67              messages: {
    68                  unknownError: 'Unknown error'  
    69              },
    70  
    71              // Function returning the current number of files,
    72              // used by the maxNumberOfFiles validation:
    73              getNumberOfFiles: function () {
    74                  return this.filesContainer.children()
    75                      .not('.processing').length;
    76              },
    77  
    78              // Callback to retrieve the list of files from the server response:
    79              getFilesFromResponse: function (data) {
    80                  if (data.result && $.isArray(data.result.files)) {
    81                      return data.result.files;
    82                  }
    83                  return [];
    84              },
    85  
    86              // The add callback is invoked as soon as files are added to the fileupload
    87              // widget (via file input selection, drag & drop or add API call).
    88              // See the basic file upload widget for more information:
    89              add: function (e, data) {
    90                  if (e.isDefaultPrevented()) {
    91                      return false;
    92                  }
    93                  var $this = $(this),
    94                      that = $this.data('blueimp-fileupload') ||
    95                          $this.data('fileupload'),
    96                      options = that.options;
    97                  data.context = that._renderUpload(data.files)
    98                      .data('data', data)
    99                      .addClass('processing');
   100                  options.filesContainer[
   101                      options.prependFiles ? 'prepend' : 'append'
   102                  ](data.context);
   103                  that._forceReflow(data.context);
   104                  that._transition(data.context);
   105                  data.process(function () {
   106                      return $this.fileupload('process', data);
   107                  }).always(function () {
   108                      data.context.each(function (index) {
   109                          $(this).find('.size').text(
   110                              that._formatFileSize(data.files[index].size)
   111                          );
   112                      }).removeClass('processing');
   113                      that._renderPreviews(data);
   114                  }).done(function () {
   115                      data.context.find('.start').prop('disabled', false);
   116                      if ((that._trigger('added', e, data) !== false) &&
   117                              (options.autoUpload || data.autoUpload) &&
   118                              data.autoUpload !== false) {
   119                          data.submit();
   120                      }
   121                  }).fail(function () {
   122                      if (data.files.error) {
   123                          data.context.each(function (index) {
   124                              var error = data.files[index].error;
   125                              if (error) {
   126                                  $(this).find('.error').text(error);
   127                              }
   128                          });
   129                      }
   130                  });
   131              },
   132              // Callback for the start of each file upload request:
   133              send: function (e, data) {
   134                  if (e.isDefaultPrevented()) {
   135                      return false;
   136                  }
   137                  var that = $(this).data('blueimp-fileupload') ||
   138                          $(this).data('fileupload');
   139                  if (data.context && data.dataType &&
   140                          data.dataType.substr(0, 6) === 'iframe') {
   141                      // Iframe Transport does not support progress events.
   142                      // In lack of an indeterminate progress bar, we set
   143                      // the progress to 100%, showing the full animated bar:
   144                      data.context
   145                          .find('.progress').addClass(
   146                              !$.support.transition && 'progress-animated'
   147                          )
   148                          .attr('aria-valuenow', 100)
   149                          .children().first().css(
   150                              'width',
   151                              '100%'
   152                          );
   153                  }
   154                  return that._trigger('sent', e, data);
   155              },
   156              // Callback for successful uploads:
   157              done: function (e, data) {
   158                  if (e.isDefaultPrevented()) {
   159                      return false;
   160                  }
   161                  var that = $(this).data('blueimp-fileupload') ||
   162                          $(this).data('fileupload'),
   163                      getFilesFromResponse = data.getFilesFromResponse ||
   164                          that.options.getFilesFromResponse,
   165                      files = getFilesFromResponse(data),
   166                      template,
   167                      deferred;
   168                  if (data.context) {
   169                      data.context.each(function (index) {
   170                          var file = files[index] ||
   171                                  {error: 'Empty file upload result'};
   172                          deferred = that._addFinishedDeferreds();
   173                          that._transition($(this)).done(
   174                              function () {
   175                                  var node = $(this);
   176                                  template = that._renderDownload([file])
   177                                      .replaceAll(node);
   178                                  that._forceReflow(template);
   179                                  that._transition(template).done(
   180                                      function () {
   181                                          data.context = $(this);
   182                                          that._trigger('completed', e, data);
   183                                          that._trigger('finished', e, data);
   184                                          deferred.resolve();
   185                                      }
   186                                  );
   187                              }
   188                          );
   189                      });
   190                  } else {
   191                      template = that._renderDownload(files)[
   192                          that.options.prependFiles ? 'prependTo' : 'appendTo'
   193                      ](that.options.filesContainer);
   194                      that._forceReflow(template);
   195                      deferred = that._addFinishedDeferreds();
   196                      that._transition(template).done(
   197                          function () {
   198                              data.context = $(this);
   199                              that._trigger('completed', e, data);
   200                              that._trigger('finished', e, data);
   201                              deferred.resolve();
   202                          }
   203                      );
   204                  }
   205              },
   206              // Callback for failed (abort or error) uploads:
   207              fail: function (e, data) {
   208                  if (e.isDefaultPrevented()) {
   209                      return false;
   210                  }
   211                  var that = $(this).data('blueimp-fileupload') ||
   212                          $(this).data('fileupload'),
   213                      template,
   214                      deferred;
   215                  if (data.context) {
   216                      data.context.each(function (index) {
   217                          if (data.errorThrown !== 'abort') {
   218                              var file = data.files[index];
   219                              file.error = file.error || data.errorThrown ||
   220                                  data.i18n('unknownError');
   221                              deferred = that._addFinishedDeferreds();
   222                              that._transition($(this)).done(
   223                                  function () {
   224                                      var node = $(this);
   225                                      template = that._renderDownload([file])
   226                                          .replaceAll(node);
   227                                      that._forceReflow(template);
   228                                      that._transition(template).done(
   229                                          function () {
   230                                              data.context = $(this);
   231                                              that._trigger('failed', e, data);
   232                                              that._trigger('finished', e, data);
   233                                              deferred.resolve();
   234                                          }
   235                                      );
   236                                  }
   237                              );
   238                          } else {
   239                              deferred = that._addFinishedDeferreds();
   240                              that._transition($(this)).done(
   241                                  function () {
   242                                      $(this).remove();
   243                                      that._trigger('failed', e, data);
   244                                      that._trigger('finished', e, data);
   245                                      deferred.resolve();
   246                                  }
   247                              );
   248                          }
   249                      });
   250                  } else if (data.errorThrown !== 'abort') {
   251                      data.context = that._renderUpload(data.files)[
   252                          that.options.prependFiles ? 'prependTo' : 'appendTo'
   253                      ](that.options.filesContainer)
   254                          .data('data', data);
   255                      that._forceReflow(data.context);
   256                      deferred = that._addFinishedDeferreds();
   257                      that._transition(data.context).done(
   258                          function () {
   259                              data.context = $(this);
   260                              that._trigger('failed', e, data);
   261                              that._trigger('finished', e, data);
   262                              deferred.resolve();
   263                          }
   264                      );
   265                  } else {
   266                      that._trigger('failed', e, data);
   267                      that._trigger('finished', e, data);
   268                      that._addFinishedDeferreds().resolve();
   269                  }
   270              },
   271              // Callback for upload progress events:
   272              progress: function (e, data) {
   273                  if (e.isDefaultPrevented()) {
   274                      return false;
   275                  }
   276                  var progress = Math.floor(data.loaded / data.total * 100);
   277                  if (data.context) {
   278                      data.context.each(function () {
   279                          $(this).find('.progress')
   280                              .attr('aria-valuenow', progress)
   281                              .children().first().css(
   282                                  'width',
   283                                  progress + '%'
   284                              );
   285                      });
   286                  }
   287              },
   288              // Callback for global upload progress events:
   289              progressall: function (e, data) {
   290                  if (e.isDefaultPrevented()) {
   291                      return false;
   292                  }
   293                  var $this = $(this),
   294                      progress = Math.floor(data.loaded / data.total * 100),
   295                      globalProgressNode = $this.find('.fileupload-progress'),
   296                      extendedProgressNode = globalProgressNode
   297                          .find('.progress-extended');
   298                  if (extendedProgressNode.length) {
   299                      extendedProgressNode.html(
   300                          ($this.data('blueimp-fileupload') || $this.data('fileupload'))
   301                              ._renderExtendedProgress(data)
   302                      );
   303                  }
   304                  globalProgressNode
   305                      .find('.progress')
   306                      .attr('aria-valuenow', progress)
   307                      .children().first().css(
   308                          'width',
   309                          progress + '%'
   310                      );
   311              },
   312              // Callback for uploads start, equivalent to the global ajaxStart event:
   313              start: function (e) {
   314                  if (e.isDefaultPrevented()) {
   315                      return false;
   316                  }
   317                  var that = $(this).data('blueimp-fileupload') ||
   318                          $(this).data('fileupload');
   319                  that._resetFinishedDeferreds();
   320                  that._transition($(this).find('.fileupload-progress')).done(
   321                      function () {
   322                          that._trigger('started', e);
   323                      }
   324                  );
   325              },
   326              // Callback for uploads stop, equivalent to the global ajaxStop event:
   327              stop: function (e) {
   328                  if (e.isDefaultPrevented()) {
   329                      return false;
   330                  }
   331                  var that = $(this).data('blueimp-fileupload') ||
   332                          $(this).data('fileupload'),
   333                      deferred = that._addFinishedDeferreds();
   334                  $.when.apply($, that._getFinishedDeferreds())
   335                      .done(function () {
   336                          that._trigger('stopped', e);
   337                      });
   338                  that._transition($(this).find('.fileupload-progress')).done(
   339                      function () {
   340                          $(this).find('.progress')
   341                              .attr('aria-valuenow', '0')
   342                              .children().first().css('width', '0%');
   343                          $(this).find('.progress-extended').html(' ');
   344                          deferred.resolve();
   345                      }
   346                  );
   347              },
   348              processstart: function (e) {
   349                  if (e.isDefaultPrevented()) {
   350                      return false;
   351                  }
   352                  $(this).addClass('fileupload-processing');
   353              },
   354              processstop: function (e) {
   355                  if (e.isDefaultPrevented()) {
   356                      return false;
   357                  }
   358                  $(this).removeClass('fileupload-processing');
   359              },
   360              // Callback for file deletion:
   361              destroy: function (e, data) {
   362                  if (e.isDefaultPrevented()) {
   363                      return false;
   364                  }
   365                  var that = $(this).data('blueimp-fileupload') ||
   366                          $(this).data('fileupload'),
   367                      removeNode = function () {
   368                          that._transition(data.context).done(
   369                              function () {
   370                                  $(this).remove();
   371                                  that._trigger('destroyed', e, data);
   372                              }
   373                          );
   374                      };
   375                  if (data.url) {
   376                      data.dataType = data.dataType || that.options.dataType;
   377                      $.ajax(data).done(removeNode).fail(function () {
   378                          that._trigger('destroyfailed', e, data);
   379                      });
   380                  } else {
   381                      removeNode();
   382                  }
   383              }
   384          },
   385  
   386          _resetFinishedDeferreds: function () {
   387              this._finishedUploads = [];
   388          },
   389  
   390          _addFinishedDeferreds: function (deferred) {
   391              if (!deferred) {
   392                  deferred = $.Deferred();
   393              }
   394              this._finishedUploads.push(deferred);
   395              return deferred;
   396          },
   397  
   398          _getFinishedDeferreds: function () {
   399              return this._finishedUploads;
   400          },
   401  
   402          // Link handler, that allows to download files
   403          // by drag & drop of the links to the desktop:
   404          _enableDragToDesktop: function () {
   405              var link = $(this),
   406                  url = link.prop('href'),
   407                  name = link.prop('download'),
   408                  type = 'application/octet-stream';
   409              link.bind('dragstart', function (e) {
   410                  try {
   411                      e.originalEvent.dataTransfer.setData(
   412                          'DownloadURL',
   413                          [type, name, url].join(':')
   414                      );
   415                  } catch (ignore) {}
   416              });
   417          },
   418  
   419          _formatFileSize: function (bytes) {
   420              if (typeof bytes !== 'number') {
   421                  return '';
   422              }
   423              if (bytes >= 1000000000) {
   424                  return (bytes / 1000000000).toFixed(2) + ' GB';
   425              }
   426              if (bytes >= 1000000) {
   427                  return (bytes / 1000000).toFixed(2) + ' MB';
   428              }
   429              return (bytes / 1000).toFixed(2) + ' KB';
   430          },
   431  
   432          _formatBitrate: function (bits) {
   433              if (typeof bits !== 'number') {
   434                  return '';
   435              }
   436              if (bits >= 1000000000) {
   437                  return (bits / 1000000000).toFixed(2) + ' Gbit/s';
   438              }
   439              if (bits >= 1000000) {
   440                  return (bits / 1000000).toFixed(2) + ' Mbit/s';
   441              }
   442              if (bits >= 1000) {
   443                  return (bits / 1000).toFixed(2) + ' kbit/s';
   444              }
   445              return bits.toFixed(2) + ' bit/s';
   446          },
   447  
   448          _formatTime: function (seconds) {
   449              var date = new Date(seconds * 1000),
   450                  days = Math.floor(seconds / 86400);
   451              days = days ? days + 'd ' : '';
   452              return days +
   453                  ('0' + date.getUTCHours()).slice(-2) + ':' +
   454                  ('0' + date.getUTCMinutes()).slice(-2) + ':' +
   455                  ('0' + date.getUTCSeconds()).slice(-2);
   456          },
   457  
   458          _formatPercentage: function (floatValue) {
   459              return (floatValue * 100).toFixed(2) + ' %';
   460          },
   461  
   462          _renderExtendedProgress: function (data) {
   463              return this._formatBitrate(data.bitrate) + ' | ' +
   464                  this._formatTime(
   465                      (data.total - data.loaded) * 8 / data.bitrate
   466                  ) + ' | ' +
   467                  this._formatPercentage(
   468                      data.loaded / data.total
   469                  ) + ' | ' +
   470                  this._formatFileSize(data.loaded) + ' / ' +
   471                  this._formatFileSize(data.total);
   472          },
   473  
   474          _renderTemplate: function (func, files) {
   475              if (!func) {
   476                  return $();
   477              }
   478              var result = func({
   479                  files: files,
   480                  formatFileSize: this._formatFileSize,
   481                  options: this.options
   482              });
   483              if (result instanceof $) {
   484                  return result;
   485              }
   486              return $(this.options.templatesContainer).html(result).children();
   487          },
   488  
   489          _renderPreviews: function (data) {
   490              data.context.find('.preview').each(function (index, elm) {
   491                  $(elm).append(data.files[index].preview);
   492              });
   493          },
   494  
   495          _renderUpload: function (files) {
   496              return this._renderTemplate(
   497                  this.options.uploadTemplate,
   498                  files
   499              );
   500          },
   501  
   502          _renderDownload: function (files) {
   503              return this._renderTemplate(
   504                  this.options.downloadTemplate,
   505                  files
   506              ).find('a[download]').each(this._enableDragToDesktop).end();
   507          },
   508  
   509          _startHandler: function (e) {
   510              e.preventDefault();
   511              var button = $(e.currentTarget),
   512                  template = button.closest('.template-upload'),
   513                  data = template.data('data');
   514              button.prop('disabled', true);
   515              if (data && data.submit) {
   516                  data.submit();
   517              }
   518          },
   519  
   520          _cancelHandler: function (e) {
   521              e.preventDefault();
   522              var template = $(e.currentTarget)
   523                      .closest('.template-upload,.template-download'),
   524                  data = template.data('data') || {};
   525              data.context = data.context || template;
   526              if (data.abort) {
   527                  data.abort();
   528              } else {
   529                  data.errorThrown = 'abort';
   530                  this._trigger('fail', e, data);
   531              }
   532          },
   533  
   534          _deleteHandler: function (e) {
   535              e.preventDefault();
   536              var button = $(e.currentTarget);
   537              this._trigger('destroy', e, $.extend({
   538                  context: button.closest('.template-download'),
   539                  type: 'DELETE'
   540              }, button.data()));
   541          },
   542  
   543          _forceReflow: function (node) {
   544              return $.support.transition && node.length &&
   545                  node[0].offsetWidth;
   546          },
   547  
   548          _transition: function (node) {
   549              var dfd = $.Deferred();
   550              if ($.support.transition && node.hasClass('fade') && node.is(':visible')) {
   551                  node.bind(
   552                      $.support.transition.end,
   553                      function (e) {
   554                          // Make sure we don't respond to other transitions events
   555                          // in the container element, e.g. from button elements:
   556                          if (e.target === node[0]) {
   557                              node.unbind($.support.transition.end);
   558                              dfd.resolveWith(node);
   559                          }
   560                      }
   561                  ).toggleClass('in');
   562              } else {
   563                  node.toggleClass('in');
   564                  dfd.resolveWith(node);
   565              }
   566              return dfd;
   567          },
   568  
   569          _initButtonBarEventHandlers: function () {
   570              var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
   571                  filesList = this.options.filesContainer;
   572              this._on(fileUploadButtonBar.find('.start'), {
   573                  click: function (e) {
   574                      e.preventDefault();
   575                      filesList.find('.start').click();
   576                  }
   577              });
   578              this._on(fileUploadButtonBar.find('.cancel'), {
   579                  click: function (e) {
   580                      e.preventDefault();
   581                      filesList.find('.cancel').click();
   582                  }
   583              });
   584              this._on(fileUploadButtonBar.find('.delete'), {
   585                  click: function (e) {
   586                      e.preventDefault();
   587                      filesList.find('.toggle:checked')
   588                          .closest('.template-download')
   589                          .find('.delete').click();
   590                      fileUploadButtonBar.find('.toggle')
   591                          .prop('checked', false);
   592                  }
   593              });
   594              this._on(fileUploadButtonBar.find('.toggle'), {
   595                  change: function (e) {
   596                      filesList.find('.toggle').prop(
   597                          'checked',
   598                          $(e.currentTarget).is(':checked')
   599                      );
   600                  }
   601              });
   602          },
   603  
   604          _destroyButtonBarEventHandlers: function () {
   605              this._off(
   606                  this.element.find('.fileupload-buttonbar')
   607                      .find('.start, .cancel, .delete'),
   608                  'click'
   609              );
   610              this._off(
   611                  this.element.find('.fileupload-buttonbar .toggle'),
   612                  'change.'
   613              );
   614          },
   615  
   616          _initEventHandlers: function () {
   617              this._super();
   618              this._on(this.options.filesContainer, {
   619                  'click .start': this._startHandler,
   620                  'click .cancel': this._cancelHandler,
   621                  'click .delete': this._deleteHandler
   622              });
   623              this._initButtonBarEventHandlers();
   624          },
   625  
   626          _destroyEventHandlers: function () {
   627              this._destroyButtonBarEventHandlers();
   628              this._off(this.options.filesContainer, 'click');
   629              this._super();
   630          },
   631  
   632          _enableFileInputButton: function () {
   633              this.element.find('.fileinput-button input')
   634                  .prop('disabled', false)
   635                  .parent().removeClass('disabled');
   636          },
   637  
   638          _disableFileInputButton: function () {
   639              this.element.find('.fileinput-button input')
   640                  .prop('disabled', true)
   641                  .parent().addClass('disabled');
   642          },
   643  
   644          _initTemplates: function () {
   645              var options = this.options;
   646              options.templatesContainer = this.document[0].createElement(
   647                  options.filesContainer.prop('nodeName')
   648              );
   649              if (tmpl) {
   650                  if (options.uploadTemplateId) {
   651                      options.uploadTemplate = tmpl(options.uploadTemplateId);
   652                  }
   653                  if (options.downloadTemplateId) {
   654                      options.downloadTemplate = tmpl(options.downloadTemplateId);
   655                  }
   656              }
   657          },
   658  
   659          _initFilesContainer: function () {
   660              var options = this.options;
   661              if (options.filesContainer === undefined) {
   662                  options.filesContainer = this.element.find('.files');
   663              } else if (!(options.filesContainer instanceof $)) {
   664                  options.filesContainer = $(options.filesContainer);
   665              }
   666          },
   667  
   668          _initSpecialOptions: function () {
   669              this._super();
   670              this._initFilesContainer();
   671              this._initTemplates();
   672          },
   673  
   674          _create: function () {
   675              this._super();
   676              this._resetFinishedDeferreds();
   677              if (!$.support.fileInput) {
   678                  this._disableFileInputButton();
   679              }
   680          },
   681  
   682          enable: function () {
   683              var wasDisabled = false;
   684              if (this.options.disabled) {
   685                  wasDisabled = true;
   686              }
   687              this._super();
   688              if (wasDisabled) {
   689                  this.element.find('input, button').prop('disabled', false);
   690                  this._enableFileInputButton();
   691              }
   692          },
   693  
   694          disable: function () {
   695              if (!this.options.disabled) {
   696                  this.element.find('input, button').prop('disabled', true);
   697                  this._disableFileInputButton();
   698              }
   699              this._super();
   700          }
   701  
   702      });
   703  
   704  }));